diff -Nru gxemul-0.6.2/configure gxemul-0.7.0+dfsg/configure --- gxemul-0.6.2/configure 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/configure 2021-11-27 09:42:23.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/sh ############################################################################### # -# Copyright (C) 2003-2019 Anders Gavare. All rights reserved. +# Copyright (C) 2003-2021 Anders Gavare. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: @@ -36,7 +36,7 @@ # # # To compile the emulator with profiling (during development), use -# CXXFLAGS="-pg", run the emulator, and then run 'gprof gxemul' and study +# CFLAGS="-pg", run the emulator, and then run 'gprof gxemul' and study # the results. # # Or better, using callgrind/cachegrind/kcachegrind: @@ -50,8 +50,8 @@ # The main things that are detected by this script: # # o) special hacks for some OSes -# o) which compiler(s) to use (overridden by setting CXX) -# o) which compiler flags to use (overridden by setting CXXFLAGS) +# o) which compiler to use (overridden by setting CC) +# o) which compiler flags to use (overridden by setting CFLAGS) # o) X11 flags and libraries (TODO: should be possible to override # via command line options?) # @@ -69,8 +69,8 @@ # DEFAULTPREFIX=/usr/local -# Special exception for Linux systems: /usr if [ z`uname` = zLinux ]; then + # /usr is more common on Linux than /usr/local DEFAULTPREFIX=/usr else TRY=/usr/local @@ -91,38 +91,21 @@ OTHERLIBS="$LDFLAGS" -UNITTESTS=YES - -# Figure out if this is a stable version (0.x.x). -X=`basename \`pwd\`|cut -d \- -f 2-|cut -c1-2` -if [ z"$X" = z0. ]; then - # Stable. - : -else - # Development. - UNSTABLE=YES -fi if [ z"$*" != z ]; then # Parse command line options: for a in $*; do if [ z$a = z--disable-x ]; then NOX11=YES - else if [ z$a = z--without-unittests ]; then - UNITTESTS=NO - else if [ z$a = z--disable-valgrind ]; then - DISABLEVALGRIND=YES else if [ z$a = z--debug ]; then DEBUG=YES else if [ z$a = z--help ]; then printf "usage: $0 [options]\n\n" echo " --disable-x don't include X11 support,"\ "even if the host supports it" - echo " --disable-valgrind don't use valgrind, even"\ - "if it is installed" - echo " --without-unittests don't include unit tests" echo " --debug configure for a" \ - "debug build (turn off optimizations)" + "debug build (turn off optimizations," + echo " try enabling -Werror etc.)" echo echo "If the PREFIX environment variable is set," \ "it will override the default" @@ -134,7 +117,7 @@ echo "Run $0 --help to get a list of" \ "available options." exit - fi; fi; fi; fi; fi + fi; fi; fi done fi @@ -164,19 +147,8 @@ fi -if [ z"$UNSTABLE" = zYES ]; then - printf "#define UNSTABLE_DEVEL\n" >> config.h -fi - -if [ z"$UNITTESTS" = zYES ]; then - printf "#define WITHUNITTESTS\n" >> config.h -fi - if [ z"$DEBUG" = zYES ]; then - echo "Building a debug version!" - CXXFLAGS="-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC $CXXFLAGS" -else - CXXFLAGS="-DNDEBUG $CXXFLAGS" + echo "Building a DEBUG version!" fi @@ -216,6 +188,10 @@ CPU_TOOLS="$CPU_TOOLS generate_arm_dpi generate_arm_r" CPU_TOOLS="$CPU_TOOLS generate_arm_loadstore generate_arm_multi" +# i960 +printf " add_cpu_family(i960_cpu_family_init, ARCH_I960);" >> config.h +CPU_ARCHS="$CPU_ARCHS cpu_i960.o memory_i960.o" + # M88K printf " add_cpu_family(m88k_cpu_family_init, ARCH_M88K);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_m88k.o memory_m88k.o" @@ -234,6 +210,10 @@ CPU_ARCHS="$CPU_ARCHS cpu_ppc.o" CPU_TOOLS="$CPU_TOOLS generate_ppc_loadstore" +# RISC-V +printf " add_cpu_family(riscv_cpu_family_init, ARCH_RISCV);" >> config.h +CPU_ARCHS="$CPU_ARCHS cpu_riscv.o memory_riscv.o" + # SuperH printf " add_cpu_family(sh_cpu_family_init, ARCH_SH);" >> config.h CPU_ARCHS="$CPU_ARCHS cpu_sh.o memory_sh.o" @@ -243,22 +223,6 @@ ############################################################################### # -# Special hacks for some host OSes: -# -############################################################################### - -if [ z"`uname|cut -c 1-6`" = zCYGWIN ]; then - CYGWIN=YES - - if [ z"$CXX" = z ]; then - # Assume GNU C++ on Cygwin (Windows) systems. - CC=g++ - fi -fi - - -############################################################################### -# # Create the Makefile header: # ############################################################################### @@ -277,71 +241,77 @@ # known to be completely broken, for instance.) echo '#include +#include -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - static int x = 0; - static int y = 1; - printf("%i,%i", x, y); - return 0; + static int s = 0; + int x = 2; // make sure that BCPL style comments work, + x ++; // that code and variable declarations can be + int y = -2; // mixed, and that the bool type behaves + bool a = x; // reasonably. + bool b = y; + bool c = a + b; + int d = a + b; + printf("%i,%i,%i,%i,%i", s, a, b, c, d); + for (int i = 0; i < 10; ++i) ; + return 0; } -' > _testprog.cc +' > _testprog.c -# Try to detect which C++ compiler to use, if CXX is not set: -printf "checking which C++ compiler to use... " +# Try to detect which C compiler to use, if CC is not set: +printf "checking which C compiler to use... " rm -f _testprog -if [ z"$CXX" = z ]; then - # Try g++ first: - printf "#!/bin/sh\ng++ $CXXFLAGS _testprog.cc -o _testprog >" > _test.sh - printf " /dev/null 2> /dev/null\n" >> _test.sh - chmod 755 _test.sh - ./_test.sh > /dev/null 2> /dev/null - if [ -x _testprog ]; then - if [ z`./_testprog` = z0,1 ]; then - CXX=g++ - else - printf "broken g++ detected\n" - printf "The test program:\n\n" - cat _testprog.cc - printf "\nshould have resulted in 0,1, but the" - printf " result was: " - ./_testprog - printf "\n\nchecking for other C++ compilers... " - fi - fi - rm -f _testprog +if [ z"$CC" = z ]; then + CC=cc +fi - # If both g++ and c++ exist, then c++ might be a vendor specific - # compiler which produces faster code: - printf "#!/bin/sh\nc++ $CXXFLAGS _testprog.cc -o _testprog >" > _test.sh - printf " /dev/null 2> /dev/null\n" >> _test.sh - chmod 755 _test.sh - ./_test.sh > /dev/null 2> /dev/null - if [ -x _testprog ]; then - if [ z`./_testprog` = z0,1 ]; then - CXX=c++ - else - printf "broken c++ detected\n" - printf "checking for other C++ compilers... " - fi +printf "#!/bin/sh\n$CC $CFLAGS _testprog.c -o _testprog >" > _test.sh +printf " /dev/null 2> /dev/null\n" >> _test.sh +chmod 755 _test.sh +./_test.sh > /dev/null 2> /dev/null +OK=0 +if [ -x _testprog ]; then + OK=1 + if [ z`./_testprog` = z0,1,1,1,2 ]; then + OK=2 fi - rm -f _testprog - rm -f _test.sh fi -rm -f _testprog +if [ z$OK = z0 ]; then + printf "broken cc detected: $CC $CFLAGS\n" + printf "The test program:\n\n" + cat _testprog.c + printf "could not be compiled at all.\n" +fi -if [ z"$CXX" = z ]; then - printf "no working compiler detected\n" - printf "\nPlease set the CXX environment variable to a working C++ " +if [ z$OK = z1 ]; then + printf "broken cc detected: $CC $CFLAGS\n" + printf "The test program:\n\n" + cat _testprog.c + printf "should have resulted in 0,1,1,1,2 but the result was: " + ./_testprog +fi + +if [ z$OK != z2 ]; then + printf "\nPlease set the CC environment variable to a working C " printf "compiler before running\nthe configure script, and make" - printf " sure that the CXXFLAGS environment variable is\nalso valid" - printf " for that compiler.\n" + printf " sure that the CFLAGS environment variable is\nalso valid" + printf " for that compiler (e.g. -std=c99 if needed).\n" exit fi -echo "$CXX $CXXFLAGS" +rm -f _testprog +rm -f _test.sh + + +echo "$CC $CFLAGS" + + +if [ z"$DEBUG" != zYES ]; then + CFLAGS="-DNDEBUG $CFLAGS" +fi if [ z$NOX11 = z ]; then @@ -355,32 +325,51 @@ dis = XOpenDisplay(NULL); } int main(int argc, char *argv[]) - { return 0; } - " > _test_x11.cc + { printf(\"1\"); return 0; } + " > _test_x11.c XOK=0 XINCLUDE=-I/usr/X11R6/include - $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null + $CC $CFLAGS _test_x11.c -c -o _test_x11.o $XINCLUDE 2> /dev/null - XLIB="-L/usr/X11R6/lib -lX11" - $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null + XLIB="-L/usr/X11R6/lib -lX11 -Wl,-rpath,/usr/X11R6/lib" + $CC $CFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then - XOK=1 + if [ 1 = `./_test_x11` ]; then + XOK=1 + fi fi rm -f _test_x11 _test_x11.o if [ z$XOK = z0 ]; then + XINCLUDE=-I/usr/X11R7/include + $CC $CFLAGS _test_x11.c -c -o _test_x11.o $XINCLUDE 2> /dev/null + + XLIB="-L/usr/X11R7/lib -lX11 -Wl,-rpath,/usr/X11R7/lib" + $CC $CFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null + + if [ -x _test_x11 ]; then + if [ 1 = `./_test_x11` ]; then + XOK=1 + fi + fi + fi + rm -f _test_x11 _test_x11.o + + if [ z$XOK = z0 ]; then XINCLUDE=-I/usr/local/include - $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null + $CC $CFLAGS _test_x11.c -c -o _test_x11.o $XINCLUDE 2> /dev/null - XLIB="-L/usr/local/lib -lX11" - $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null + XLIB="-L/usr/local/lib -lX11 -Wl,-rpath,/usr/local/lib" + $CC $CFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then - XOK=1 + if [ 1 = `./_test_x11` ]; then + XOK=1 + fi fi fi rm -f _test_x11 _test_x11.o @@ -388,10 +377,10 @@ # MacOS: if [ z$XOK = z0 ]; then XINCLUDE=-I/opt/X11/include - $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null + $CC $CFLAGS _test_x11.c -c -o _test_x11.o $XINCLUDE 2> /dev/null XLIB="-L/opt/X11/lib -lX11" - $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null + $CC $CFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then XOK=1 @@ -401,87 +390,79 @@ # Special case for some 64-bit Linux/x86_64 systems: if [ z$XOK = z0 ]; then - $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null + $CC $CFLAGS _test_x11.c -c -o _test_x11.o $XINCLUDE 2> /dev/null XLIB="-L/usr/X11R6/lib64 -lX11" - $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null + $CC $CFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then - XOK=1 + if [ 1 = `./_test_x11` ]; then + XOK=1 + fi fi fi rm -f _test_x11 _test_x11.o if [ z$XOK = z0 ]; then XINCLUDE="" - $CXX $CXXFLAGS _test_x11.cc -c -o _test_x11.o $XINCLUDE 2> /dev/null + $CC $CFLAGS _test_x11.c -c -o _test_x11.o $XINCLUDE 2> /dev/null # -lsocket for Solaris XLIB="-lX11 -lsocket" - $CXX $CXXFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null + $CC $CFLAGS _test_x11.o -o _test_x11 $XLIB 2> /dev/null if [ -x _test_x11 ]; then - XOK=1 + if [ 1 = `./_test_x11` ]; then + XOK=1 + fi fi rm -f _test_x11 _test_x11.o fi - if [ z`uname` = zNetBSD ]; then - echo "Using NetBSD hack for X11 libs..." - XLIB="$XLIB -Wl,-rpath,/usr/X11R6/lib" - fi - - if [ z`uname` = zOpenBSD ]; then - if [ z`uname -m` = zarc ]; then - echo "Using old OpenBSD/arc hack for X11 libs..." - XLIB="$XLIB -Wl,-rpath,/usr/X11R6/lib" - fi - fi - if [ z$XOK = z0 ]; then echo "Failed to compile X11 test program." \ "Configuring without X11." else - printf "X11 headers: $XINCLUDE\n" - printf "X11 libraries: $XLIB\n" + printf " headers: $XINCLUDE\n" + printf " libraries: $XLIB\n" echo "XINCLUDE=$XINCLUDE" >> _Makefile.header echo "XLIB=$XLIB" >> _Makefile.header printf "#define WITH_X11\n" >> config.h fi - rm -f _test_x11.cc + rm -f _test_x11.c fi if [ z$HPUX = zYES ]; then - CXXFLAGS="-D_XOPEN_SOURCE_EXTENDED $CXXFLAGS" + CFLAGS="-D_XOPEN_SOURCE_EXTENDED $CFLAGS" printf "#define HPUX\n" >> config.h fi if [ z$OSF1 = zYES ]; then - CXXFLAGS="-D_XOPEN_SOURCE=500 -D_OSF_SOURCE -D_POSIX_PII_SOCKET $CXXFLAGS" + CFLAGS="-D_XOPEN_SOURCE=500 -D_OSF_SOURCE -D_POSIX_PII_SOCKET $CFLAGS" fi # CWARNINGS: printf "checking whether -Wall can be used... " -$CXX $CXXFLAGS _testprog.cc -o _testprog -Wall 2> /dev/null +$CC $CFLAGS _testprog.c -o _testprog -Wall 2> /dev/null if [ -x _testprog ]; then printf "yes\n" CWARNINGS="-Wall $CWARNINGS" - if [ z"$UNSTABLE" = zYES ]; then + if [ z"$DEBUG" = zYES ]; then printf "checking whether -Werror can be used... " rm -f _testprog - $CXX $CWARNINGS $CXXFLAGS _testprog.cc -o _testprog -Werror 2> _testprog.err + $CC $CWARNINGS $CFLAGS _testprog.c -o _testprog -Werror 2> _testprog.err if [ -x _testprog ]; then printf "yes\n" -# CWARNINGS="$CWARNINGS -Werror" + CWARNINGS="$CWARNINGS -Werror" else printf "no\n" - #printf "CXXFLAGS = $CXXFLAGS\n" + #printf "CFLAGS = $CFLAGS\n" #cat _testprog.err #printf "\n" fi @@ -494,7 +475,7 @@ # -Wstrict-aliasing printf "checking whether -Wstrict-aliasing can be used... " -$CXX $CXXFLAGS -Wstrict-aliasing _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 +$CC $CFLAGS -Wstrict-aliasing _testprog.c -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" @@ -509,26 +490,9 @@ rm -f _testprog _testprog.error _testprog.stdout -# -Wnon-virtual-dtor -printf "checking whether -Wnon-virtual-dtor can be used... " -$CXX $CXXFLAGS -Wnon-virtual-dtor _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 -cat _testprog.stdout >> _testprog.error -if grep strict _testprog.error > /dev/null 2>&1; then - printf "no\n" -else - if [ -x _testprog ]; then - CWARNINGS="-Wnon-virtual-dtor $CWARNINGS" - printf "yes\n" - else - printf "no\n" - fi -fi -rm -f _testprog _testprog.error _testprog.stdout - - # -Wextra -Wno-unused-parameter -Wno-cast-align printf "checking whether -Wextra -Wno-unused-parameter -Wno-cast-align can be used... " -$CXX $CXXFLAGS -Wextra -Wno-unused-parameter -Wno-cast-align _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 +$CC $CFLAGS -Wextra -Wno-unused-parameter -Wno-cast-align _testprog.c -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" @@ -545,7 +509,7 @@ # -Wcast-align printf "checking whether -Wcast-align can be used... " -$CXX $CXXFLAGS -Wcast-align _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 +$CC $CFLAGS -Wcast-align _testprog.c -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" @@ -560,26 +524,9 @@ rm -f _testprog _testprog.error _testprog.stdout -# -Wcast-qual -#printf "checking whether -Wcast-qual can be used... " -#$CXX $CXXFLAGS -Wcast-qual _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 -#cat _testprog.stdout >> _testprog.error -#if grep strict _testprog.error > /dev/null 2>&1; then - #printf "no\n" -#else - #if [ -x _testprog ]; then -# CWARNINGS="-Wcast-qual $CWARNINGS" - #printf "yes\n" -# else - #printf "no\n" -# fi -#fi -#rm -f _testprog _testprog.error _testprog.stdout - - # -Wshadow printf "checking whether -Wshadow can be used... " -$CXX $CXXFLAGS -Wshadow _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 +$CC $CFLAGS -Wshadow _testprog.c -o _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" @@ -596,15 +543,20 @@ # -O optimization for non-debug builds. Try -O and -O3. if [ ! z"$DEBUG" = zYES ]; then - $CXX $CXXFLAGS -O _testprog.cc -o _testprog 2> /dev/null + printf "checking whether -O3 or -O can be used (non-DEBUG build)... " + $CC $CFLAGS -O _testprog.c -o _testprog 2> /dev/null if [ -x _testprog ]; then rm -f _testprog - $CXX $CXXFLAGS -O3 _testprog.cc -o _testprog 2> /dev/null + $CC $CFLAGS -O3 _testprog.c -o _testprog 2> /dev/null if [ -x _testprog ]; then - CXXFLAGS="-O3 $CXXFLAGS" + CFLAGS="-O3 $CFLAGS" + printf "yes, -O3\n" else - CXXFLAGS="-O $CXXFLAGS" + CFLAGS="-O $CFLAGS" + printf "yes, -O\n" fi + else + printf "no\n" fi fi rm -f _testprog @@ -613,13 +565,13 @@ # -fpeephole if [ ! z"$DEBUG" = zYES ]; then printf "checking whether -fpeephole can be used... " - $CXX $CXXFLAGS -fpeephole _testprog.cc -o _testprog > _testprog.stdout 2>&1 + $CC $CFLAGS -fpeephole _testprog.c -o _testprog > _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep peephole _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then - CXXFLAGS="-fpeephole $CXXFLAGS" + CFLAGS="-fpeephole $CFLAGS" printf "yes\n" else printf "no\n" @@ -632,14 +584,14 @@ # -fomit-frame-pointer if [ ! z"$DEBUG" = zYES ]; then printf "checking whether -fomit-frame-pointer can be used... " - $CXX $CXXFLAGS -fomit-frame-pointer _testprog.cc -o \ + $CC $CFLAGS -fomit-frame-pointer _testprog.c -o \ _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep frame _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then - CXXFLAGS="-fomit-frame-pointer $CXXFLAGS" + CFLAGS="-fomit-frame-pointer $CFLAGS" printf "yes\n" else printf "no\n" @@ -652,14 +604,14 @@ # -fstrict-aliasing if [ ! z"$DEBUG" = zYES ]; then printf "checking whether -fstrict-aliasing can be used... " - $CXX $CXXFLAGS -fstrict-aliasing _testprog.cc -o \ + $CC $CFLAGS -fstrict-aliasing _testprog.c -o \ _testprog 1> _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if grep strict _testprog.error > /dev/null 2>&1; then printf "no\n" else if [ -x _testprog ]; then - CXXFLAGS="-fstrict-aliasing $CXXFLAGS" + CFLAGS="-fstrict-aliasing $CFLAGS" printf "yes\n" else printf "no\n" @@ -669,32 +621,13 @@ fi -# -fno-rtti -if [ ! z"$DEBUG" = zYES ]; then - printf "checking whether -fno-rtti can be used... " - $CXX $CXXFLAGS -fno-rtti _testprog.cc -o _testprog 1> _testprog.stdout 2>&1 - cat _testprog.stdout >> _testprog.error - if grep rtti _testprog.error > /dev/null 2>&1; then - printf "no\n" - else - if [ -x _testprog ]; then - CXXFLAGS="-fno-rtti $CXXFLAGS" - printf "yes\n" - else - printf "no\n" - fi - fi - rm -f _testprog _testprog.error _testprog.stdout -fi - - -# -g, for development builds -if [ z"$UNSTABLE" = zYES ]; then +# -g, for debug builds +if [ z"$DEBUG" = zYES ]; then printf "checking whether -g can be used... " - $CXX $CXXFLAGS -g _testprog.cc -o _testprog > _testprog.stdout 2>&1 + $CC $CFLAGS -g _testprog.c -o _testprog > _testprog.stdout 2>&1 cat _testprog.stdout >> _testprog.error if [ -x _testprog ]; then - CXXFLAGS="-g $CXXFLAGS" + CFLAGS="-g $CFLAGS" printf "yes\n" else printf "no\n" @@ -706,10 +639,10 @@ # -lrt for nanosleep? printf "checking whether -lrt is required for nanosleep... " printf "#include \n#include -int main(int argc, char *argv[]){nanosleep(NULL,NULL);return 0;}\n" > _testns.cc -$CXX $CXXFLAGS _testns.cc -o _testns 2> /dev/null +int main(int argc, char *argv[]){nanosleep(NULL,NULL);return 0;}\n" > _testns.c +$CC $CFLAGS _testns.c -o _testns 2> /dev/null if [ ! -x _testns ]; then - $CXX $CXXFLAGS -lrt _testns.cc -o _testns 2> /dev/null + $CC $CFLAGS -lrt _testns.c -o _testns 2> /dev/null if [ ! -x _testns ]; then printf "WARNING! COULD NOT COMPILE WITH nanosleep AT ALL!\n" else @@ -720,18 +653,18 @@ else printf "no\n" fi -rm -f _testns.cc _testns +rm -f _testns.c _testns # -lresolv for inet_pton? printf "checking whether -lresolv is required for inet_pton... " -printf "int inet_pton(void); int main(int argc, " > _testr.cc -printf "char *argv[]) { return inet_pton(); }\n" >> _testr.cc -$CXX $CXXFLAGS _testr.cc -o _testr 2> /dev/null +printf "int inet_pton(void); int main(int argc, " > _testr.c +printf "char *argv[]) { return inet_pton(); }\n" >> _testr.c +$CC $CFLAGS _testr.c -o _testr 2> /dev/null if [ ! -x _testr ]; then - $CXX $CXXFLAGS _testr.cc -lresolv -o _testr 2> /dev/null + $CC $CFLAGS _testr.c -lresolv -o _testr 2> /dev/null if [ ! -x _testr ]; then - $CXX $CXXFLAGS _testr.cc -lresolv -lnsl -o _testr 2> /dev/null + $CC $CFLAGS _testr.c -lresolv -lnsl -o _testr 2> /dev/null if [ ! -x _testr ]; then printf "no, using inet_aton\n" else @@ -750,18 +683,18 @@ printf "no\n" printf "#define HAVE_INET_PTON\n" >> config.h fi -rm -f _testr.cc _testr.o _testr +rm -f _testr.c _testr.o _testr # -lm? printf "checking for math libs..." -printf "#include \nint main(int argc, char *argv[]) { " > _testr.cc -printf "double x = sqrt(sin((double)argc)); return (int)x; }\n" >> _testr.cc -$CXX $CXXFLAGS _testr.cc -o _testr 2> /dev/null +printf "#include \nint main(int argc, char *argv[]) { " > _testr.c +printf "double x = sqrt(sin((double)argc)); return (int)x; }\n" >> _testr.c +$CC $CFLAGS _testr.c -o _testr 2> /dev/null if [ ! -x _testr ]; then - $CXX $CXXFLAGS _testr.cc -lm -o _testr 2> /dev/null + $CC $CFLAGS _testr.c -lm -o _testr 2> /dev/null if [ ! -x _testr ]; then - $CXX $CXXFLAGS _testr.cc -lm -lcpml -o _testr 2> /dev/null + $CC $CFLAGS _testr.c -lm -lcpml -o _testr 2> /dev/null if [ ! -x _testr ]; then printf "\nWARNING! Could not compile math test " printf "at all!\nContinuing anyway.\n\n" @@ -778,15 +711,15 @@ else printf " none needed\n" fi -rm -f _testr.cc _testr.o _testr +rm -f _testr.c _testr.o _testr # strlcpy missing? printf "checking for strlcpy... " printf "#include int main(int argc, char *argv[]) { char *p; char *q; size_t x; - x = strlcpy(p, q, 50); return 0;}\n" > _tests.cc -$CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null + x = strlcpy(p, q, 50); return 0;}\n" > _tests.c +$CC $CFLAGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing, using mystrlcpy\n" printf "#define strlcpy mystrlcpy\n" >> config.h @@ -795,7 +728,7 @@ else printf "found\n" fi -rm -f _tests.cc _tests.o _tests +rm -f _tests.c _tests.o _tests # strtoull missing? @@ -804,15 +737,15 @@ #include #include int main(int argc, char *argv[]) { - long long x = strtoull(argv[1], NULL, 0); return 0;}\n" > _tests.cc -$CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null + long long x = strtoull(argv[1], NULL, 0); return 0;}\n" > _tests.c +$CC $CFLAGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing, using mystrtoull\n" printf "#define strtoull mystrtoull\n" >> config.h else printf "found\n" fi -rm -f _tests.cc _tests.o _tests +rm -f _tests.c _tests.o _tests # mkstemp missing? @@ -820,15 +753,15 @@ printf "#include #include int main(int argc, char *argv[]) { int x; char y[4] = \"abc\"; -x = mkstemp(y); return 0;}\n" > _tests.cc -$CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null +x = mkstemp(y); return 0;}\n" > _tests.c +$CC $CFLAGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing, using workaround (perhaps not working properly)\n" printf "#define mkstemp mymkstemp\n" >> config.h else printf "found\n" fi -rm -f _tests.cc _tests.o _tests +rm -f _tests.c _tests.o _tests # fseeko missing? @@ -837,12 +770,12 @@ #include #include #include -int main(int argc, char *argv[]) { fseeko(NULL, 0, 0); return 0;}\n" > _tests.cc -$CXX $CXXFLAGS $CWARNINGS _tests.cc -o _tests 2> /dev/null +int main(int argc, char *argv[]) { fseeko(NULL, 0, 0); return 0;}\n" > _tests.c +$CC $CFLAGS $CWARNINGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then # Try with _LARGEFILE_SOURCE (hack to make fseeko # work on 64-bit Linux): - $CXX $CXXFLAGS -D_LARGEFILE_SOURCE $CWARNINGS _tests.cc -o _tests 2> /dev/null + $CC $CFLAGS -D_LARGEFILE_SOURCE $CWARNINGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "missing\n" printf "WARNING! fseeko missing from libc. Using a hack, " @@ -850,12 +783,12 @@ printf "#define HACK_FSEEKO\n" >> config.h else printf "using -D_LARGEFILE_SOURCE hack\n" - CXXFLAGS="$CXXFLAGS -D_LARGEFILE_SOURCE" + CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE" fi else printf "found\n" fi -rm -f _tests.cc _tests.o _tests +rm -f _tests.c _tests.o _tests # socklen_t missing? @@ -865,15 +798,15 @@ #include #include #include -int main(int argc, char *argv[]) { socklen_t x; return 0;}\n" > _tests.cc -$CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null +int main(int argc, char *argv[]) { socklen_t x; return 0;}\n" > _tests.c +$CC $CFLAGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "no, using int\n" - CXXFLAGS="$CXXFLAGS -Dsocklen_t=int" + CFLAGS="$CFLAGS -Dsocklen_t=int" else printf "socklen_t\n" fi -rm -f _tests.cc _tests.o _tests +rm -f _tests.c _tests.o _tests # MAP_ANON missing? (On some HP-UX systems? Use MAP_ANONYMOUS instead.) @@ -882,15 +815,15 @@ printf "#include #include #include -int main(int argc, char *argv[]) { int x = MAP_ANON; return 0;}\n" > _tests.cc -$CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null +int main(int argc, char *argv[]) { int x = MAP_ANON; return 0;}\n" > _tests.c +$CC $CFLAGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "#include #include #include int main(int argc, char *argv[]) -{ int x = MAP_ANONYMOUS; return 0;}\n" > _tests.cc - $CXX $CXXFLAGS _tests.cc -o _tests 2> /dev/null +{ int x = MAP_ANONYMOUS; return 0;}\n" > _tests.c + $CC $CFLAGS _tests.c -o _tests 2> /dev/null if [ ! -x _tests ]; then printf "no\n\n" printf "WARNING! Neither MAP_ANON nor MAP_ANONYMOUS work on " @@ -905,14 +838,14 @@ else printf "yes\n" fi -rm -f _tests.cc _tests.o _tests +rm -f _tests.c _tests.o _tests # Check for PRIx64 in inttypes.h: printf "checking for PRIx64 in inttypes.h... " printf "#include \nint main(int argc, char *argv[])\n -{\n#ifdef PRIx64\nreturn 0;\n#else\nreturn 1;\n#endif\n}\n" > _testpri.cc -$CXX $CXXFLAGS _testpri.cc -o _testpri 2> /dev/null +{\n#ifdef PRIx64\nreturn 0;\n#else\nreturn 1;\n#endif\n}\n" > _testpri.c +$CC $CFLAGS _testpri.c -o _testpri 2> /dev/null if [ ! -x _testpri ]; then printf "\nERROR! COULD NOT COMPILE PRIx64 TEST PROGRAM AT ALL!\n" exit @@ -920,28 +853,28 @@ if ./_testpri; then printf "yes\n" else - $CXX $CXXFLAGS -D__STDC_FORMAT_MACROS _testpri.cc -o _testpri 2> /dev/null + $CC $CFLAGS -D__STDC_FORMAT_MACROS _testpri.c -o _testpri 2> /dev/null if [ -x _testpri ]; then printf "using __STDC_FORMAT_MACROS\n" - CXXFLAGS="$CXXFLAGS -D__STDC_FORMAT_MACROS" + CFLAGS="$CFLAGS -D__STDC_FORMAT_MACROS" else printf "no, using an ugly hack instead, " printf "#define NO_C99_PRINTF_DEFINES\n" >> config.h # Try llx first: printf "#include \n#include \nint main(int argc, char *argv[]){ - printf(\"%%llx\\\n\", (int64_t)128);return 0;}\n" > _testpri.cc + printf(\"%%llx\\\n\", (int64_t)128);return 0;}\n" > _testpri.c rm -f _testpri - $CXX $CXXFLAGS $CWARNINGS _testpri.cc -o _testpri 2> /dev/null + $CC $CFLAGS $CWARNINGS _testpri.c -o _testpri 2> /dev/null if [ z`./_testpri` = z80 ]; then printf "PRIx64=llx\n" printf "#define NO_C99_64BIT_LONGLONG\n" >> config.h else # Try lx too: printf "#include \n#include \nint main(int argc, char *argv[]){ - printf(\"%%lx\\\n\", (int64_t)128);return 0;}\n" > _testpri.cc + printf(\"%%lx\\\n\", (int64_t)128);return 0;}\n" > _testpri.c rm -f _testpri - $CXX $CXXFLAGS $CWARNINGS _testpri.cc -o _testpri 2> _testpri.result + $CC $CFLAGS $CWARNINGS _testpri.c -o _testpri 2> _testpri.result if [ z`./_testpri` = z80 ]; then printf "PRIx64=lx\n" else @@ -952,30 +885,30 @@ fi fi fi -rm -f _testpri.cc _testpri _testpri.result +rm -f _testpri.c _testpri _testpri.result # Check for 64-bit off_t: printf "checking for 64-bit off_t... " printf "#include \n#include \n#include \n int main(int argc, char *argv[]){printf(\"%%i\\\n\", - (int)sizeof(off_t));return 0;}\n" > _testoff.cc -$CXX $CXXFLAGS _testoff.cc -o _testoff 2> /dev/null + (int)sizeof(off_t));return 0;}\n" > _testoff.c +$CC $CFLAGS _testoff.c -o _testoff 2> /dev/null if [ ! -x _testoff ]; then printf "\nWARNING! COULD NOT COMPILE off_t TEST PROGRAM AT ALL!\n" else if [ z`./_testoff` = z8 ]; then printf "yes\n" else - $CXX $CXXFLAGS -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ - _testoff.cc -o _testoff 2> /dev/null + $CC $CFLAGS -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ + _testoff.c -o _testoff 2> /dev/null if [ ! -x _testoff ]; then printf "\nWARNING! COULD NOT COMPILE off_t TEST " printf "PROGRAM!\n" else if [ z`./_testoff` = z8 ]; then - CXXFLAGS="-D_FILE_OFFSET_BITS=64 $CXXFLAGS" - CXXFLAGS="-D_LARGEFILE_SOURCE $CXXFLAGS" + CFLAGS="-D_FILE_OFFSET_BITS=64 $CFLAGS" + CFLAGS="-D_LARGEFILE_SOURCE $CFLAGS" printf "using -D_FILE_OFFSET_BITS=64" printf " -D_LARGEFILE_SOURCE\n" else @@ -986,7 +919,7 @@ fi fi fi -rm -f _testoff.cc _testoff +rm -f _testoff.c _testoff # Check for u_int8_t etc: @@ -995,14 +928,14 @@ printf "checking for u_int8_t... " printf "#include \n#include \n#include \n int main(int argc, char *argv[]){printf(\"%%i\\\n\", - (int)sizeof(u_int8_t));return 0;}\n" > _testuint.cc -$CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null + (int)sizeof(u_int8_t));return 0;}\n" > _testuint.c +$CC $CFLAGS _testuint.c -o _testuint 2> /dev/null if [ ! -x _testuint ]; then rm -f _testuint* printf "#include \n#include \n#include \nint main(int argc, char *argv[]) - {printf(\"%%i\\\n\", (int)sizeof(uint8_t));return 0;}\n" > _testuint.cc - $CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null + {printf(\"%%i\\\n\", (int)sizeof(uint8_t));return 0;}\n" > _testuint.c + $CC $CFLAGS _testuint.c -o _testuint 2> /dev/null if [ ! -x _testuint ]; then printf "no\n\nERROR: No u_int8_t or uint8_t. Aborting\n" # TODO: Automagically detect using various combinations @@ -1017,19 +950,19 @@ else printf "yes\n" fi -rm -f _testuint.cc _testuint +rm -f _testuint.c _testuint printf "checking for u_int64_t... " printf "#include \n#include \n#include \n int main(int argc, char *argv[]){printf(\"%%i\\\n\", - (int)sizeof(u_int64_t));return 0;}\n" > _testuint.cc -$CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null + (int)sizeof(u_int64_t));return 0;}\n" > _testuint.c +$CC $CFLAGS _testuint.c -o _testuint 2> /dev/null if [ ! -x _testuint ]; then rm -f _testuint* printf "#include \n#include \n#include \nint main(int argc, char *argv[]) - {printf(\"%%i\\\n\", (int)sizeof(uint64_t));return 0;}\n" > _testuint.cc - $CXX $CXXFLAGS _testuint.cc -o _testuint 2> /dev/null + {printf(\"%%i\\\n\", (int)sizeof(uint64_t));return 0;}\n" > _testuint.c + $CC $CFLAGS _testuint.c -o _testuint 2> /dev/null if [ ! -x _testuint ]; then printf "no\n\nERROR: No u_int64_t or uint64_t. Aborting\n" # TODO: Automagically detect using various combinations @@ -1044,26 +977,10 @@ fi rm -f _testuint* -printf "checking for __FUNCTION__... " -printf "#include \n\nint main(int argc, char *argv[]) { - if (__FUNCTION__) printf(__FUNCTION__);\n return 0;\n}\n" > _testfunction.cc -$CXX $CXXFLAGS _testfunction.cc -o _testfunction 2> /dev/null -if [ ! -x _testfunction ]; then - printf "no\n" -else - if [ z`./_testfunction` = zmain ]; then - printf "yes\n" - printf "#define HAVE___FUNCTION__\n" >> config.h - else - printf "no\n" - fi -fi -rm -f _testfunction* - printf "checking for __builtin_expect... " printf "#include \n\nint main(int argc, char *argv[]) { - if (__builtin_expect(!!(2), 1)) return 0;\n return 1;\n}\n" > _testexpect.cc -$CXX $CXXFLAGS _testexpect.cc -o _testexpect 2> /dev/null + if (__builtin_expect(!!(2), 1)) return 0;\n return 1;\n}\n" > _testexpect.c +$CC $CFLAGS _testexpect.c -o _testexpect 2> /dev/null if [ ! -x _testexpect ]; then printf "no\n" printf "#define likely(x) (x)\n" >> config.h @@ -1085,8 +1002,8 @@ int main(int argc, char *argv[]) { int x = 1; void *xp = (void *)&x; char *p = (char *)xp; if (*p) printf("little\\\n"); else printf("big\\\n"); } -' > _test_end.cc -$CXX $CXXFLAGS _test_end.cc -o _test_end 2> /dev/null +' > _test_end.c +$CC $CFLAGS _test_end.c -o _test_end 2> /dev/null X=`./_test_end` echo $X if [ z$X = zlittle ]; then @@ -1104,36 +1021,6 @@ ############################################################################### -printf "checking for Doxygen... " - -if (doxygen --version); then - # Version is printed, if found. - DOXYGEN=doxygen -else - # Not found is already printed, if doxygen is not found. - DOXYGEN="\#" -fi - - -############################################################################### - -printf "checking for valgrind... " - -if [ z$DISABLEVALGRIND = zYES ]; then - echo skipped -else - if (valgrind --version); then - # Version is printed, if found. - VALGRIND="valgrind -q --log-file=tmp_valgrind.out" - else - # Not found is already printed, if valgrind is not found. - VALGRIND="" - fi -fi - - -############################################################################### - if [ "z$PREFIX" = z ]; then PREFIX="$DEFAULTPREFIX" fi @@ -1163,85 +1050,31 @@ rm -f _testprog.c* -echo C++ compiler flags: $CXXFLAGS $CWARNINGS +echo C compiler flags: $CFLAGS $CWARNINGS echo Linker flags: $OTHERLIBS if [ z"$DESTDIR" != z ]; then echo "Destination dir: $DESTDIR" fi echo "CWARNINGS=$CWARNINGS" >> _Makefile.header -echo "COPTIM=$CXXFLAGS" >> _Makefile.header +echo "COPTIM=$CFLAGS" >> _Makefile.header echo "INCLUDE=$INCLUDE" >> _Makefile.header echo "DINCLUDE=$DINCLUDE" >> _Makefile.header echo "INCLUDE2=$INCLUDE2" >> _Makefile.header -echo "CXX=$CXX" >> _Makefile.header +echo "CC=$CC" >> _Makefile.header echo "OTHERLIBS=$OTHERLIBS" >> _Makefile.header echo "CPU_ARCHS=$CPU_ARCHS" >> _Makefile.header echo "CPU_TOOLS=$CPU_TOOLS" >> _Makefile.header -echo "DOXYGEN=$DOXYGEN" >> _Makefile.header -echo "VALGRIND=$VALGRIND" >> _Makefile.header echo "PREFIX=$PREFIX" >> _Makefile.header echo "MANDIR=$MANDIR" >> _Makefile.header echo "DESTDIR=$DESTDIR" >> _Makefile.header echo "" >> _Makefile.header -# Create list of unit testable classes: -rm -f unittest.h unittest_h.h -printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> unittest.h -printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> unittest_h.h -printf "// Will be removed by make clean_all\n\n" >> unittest.h -printf "// Will be removed by make clean_all\n\n" >> unittest_h.h -for a in `find src -name "*.cc" -print`; do grep UNITTESTS\( "$a"; - done | cut -d \( -f 2|cut -d \) -f 1 > _unittests.tmp -for a in `cat _unittests.tmp`; do - if [ ! z$a = zclassName ]; then - cd src/include - HNAME=`find . -name $a.h | cut -c 3-` - cd ../.. - printf "#include \"$HNAME\"\n" >> unittest_h.h - printf "\t$a::RunUnitTests(nSucceeded, nFailed);\n" >> unittest.h - fi -done -rm -f _unittests.tmp - -# Create a list of Commands: -rm -f commands_h.h commands.h -printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> commands.h -printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> commands_h.h -printf "// Will be removed by make clean_all\n\n" >> commands.h -printf "// Will be removed by make clean_all\n\n" >> commands_h.h -for a in src/main/commands/*.cc; do echo $a|cut -d / -f 4-; done > _commands.tmp -for a in `cat _commands.tmp`; do - CNAME=`echo $a|cut -d . -f 1` - printf "#include \"commands/$CNAME.h\"\n" >> commands_h.h - printf "\tAddCommand(new $CNAME);\n" >> commands.h -done -rm -f _commands.tmp - -# Create a list of Components: -rm -f components.h components_h.h -printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> components.h -printf "// DO NOT EDIT. Automagically generated by the configure script.\n" >> components_h.h -printf "// Will be removed by make clean_all\n\n" >> components.h -printf "// Will be removed by make clean_all\n\n" >> components_h.h -grep COMPONENT\( src/include/components/*.h|cut -d \( -f 2|cut -d \) -f 1 > _components.tmp -cd src/include/components -for a in `cat ../../../_components.tmp`; do - CNAME=`grep COMPONENT\($a\) *.h|cut -d . -f 1` - printf "#include \"components/$CNAME.h\"\n" >> ../../../components_h.h - printf "\t{ \"$a\", $CNAME::Create, $CNAME::GetAttribute },\n" >> ../../../components.h -done -cd ../../.. -rm -f _components.tmp - # Create the Makefiles: -D=". src src/components src/components/busses src/components/cpu" -D="$D src/components/machines src/components/memory src/components/special" -D="$D src/console src/cpus src/debugger src/devices src/old_main" -D="$D src/devices/fonts src/disk src/file src/include src/machines src/main" -D="$D src/main/commands src/main/fileloaders src/net" -D="$D src/promemul src/symbol src/ui src/ui/console src/ui/nullui" +D=". src src/console src/cpus src/debugger src/devices src/core" +D="$D src/devices/fonts src/disk src/file src/include src/machines" +D="$D src/net src/promemul src/symbol" +echo "creating Makefiles..." for a in $D; do - echo "creating $a/Makefile" touch $a/Makefile cat _Makefile.header > $a/Makefile cat $a/Makefile.skel >> $a/Makefile @@ -1256,5 +1089,5 @@ # Remove temporary Makefile header, etc.: rm -f _Makefile.header _test* -echo Configured. You may now run make to build gxemul. +echo Configured. You may now run ' make ' to build gxemul. diff -Nru gxemul-0.6.2/debian/changelog gxemul-0.7.0+dfsg/debian/changelog --- gxemul-0.6.2/debian/changelog 2020-08-25 19:25:06.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/changelog 2021-11-27 12:34:13.000000000 +0000 @@ -1,3 +1,22 @@ +gxemul (0.7.0+dfsg-1) unstable; urgency=medium + + * New upstream version + * debian/gbp.conf: Fix upstream-tag template + * debian/control: Update the list of supported systems + * debian/copyright: Update to reflect upstream changes + * debian/control: Mark gxemul as Multi-Arch: foreign + * debian/rules: Remove --disable-valgrind flag; no longer exists + * debian/rules: Sprinkle reproducible dust on the config + * debian/patches/remove_defines: Upstream patch for a build failure + * debian/rules: Remove -rpath flag after configuration + * debian/copyright: Exclude test/FileLoader*; trivial but missing source + * debian/watch: Add +dfsg on the repacked source + * debian/rules: Remove useless fiddling with CFLAGS + * debian/control: Remove unused doxygen build-dep + * debian/rules: Support cross-compilation + + -- Göran Weinholt Sat, 27 Nov 2021 13:34:13 +0100 + gxemul (0.6.2-2) unstable; urgency=medium [ Debian Janitor ] diff -Nru gxemul-0.6.2/debian/control gxemul-0.7.0+dfsg/debian/control --- gxemul-0.6.2/debian/control 2020-08-25 19:23:57.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/control 2021-11-27 11:59:16.000000000 +0000 @@ -2,7 +2,7 @@ Section: misc Priority: optional Maintainer: Göran Weinholt -Build-Depends: debhelper-compat (= 11), libx11-dev, doxygen +Build-Depends: debhelper-compat (= 11), libx11-dev Standards-Version: 4.5.0 Homepage: http://gavare.se/gxemul/ Vcs-Browser: https://salsa.debian.org/debian/gxemul @@ -19,28 +19,31 @@ system: . ARM-based machines: - * CATS (NetBSD/cats, OpenBSD/cats) + * CATS (NetBSD/cats, OpenBSD/cats, Debian GNU/Linux) * IQ80321 (NetBSD/evbarm) * NetWinder (NetBSD/netwinder) + * Raspberry Pi (NetBSD/raspberrypi, FreeBSD, HelenOS/rpi) MIPS-based machines: - * DECstation 5000/200 (NetBSD/pmax, OpenBSD/pmax, Ultrix, - Linux/DECstation, Sprite) - * Acer Pica-61 (NetBSD/arc) - * NEC MobilePro 770, 780, 800, 880 (NetBSD/hpcmips) + * Acer Pica-61 (NetBSD/arc, Windows NT) + * Algorithmics P5064 (NetBSD/algor) * Cobalt (NetBSD/cobalt) + * DECstation 5000/200 (NetBSD/pmax, OpenBSD/pmax, Ultrix, + Linux/DECstation, Sprite), DECstation 5000/1xx (raw PROM) * Malta (NetBSD/evbmips, Linux/Malta) - * Algorithmics P5064 (NetBSD/algor) - * SGI O2 (aka IP32) (NetBSD/sgi) + * NEC MobilePro 770, 780, 800, 880 (NetBSD/hpcmips) + * PlayStation 2 (NetBSD/playstation2) + * SGI O2 (NetBSD/sgimips, OpenBSD/sgi, Linux, IRIX, raw PROM) + * VoCore (FreeBSD/vocore, Linux/vocore) Motorola 88K-based machines: - * Motorola MVME187 (OpenBSD/mvme88k) * Luna 88K (OpenBSD/luna88k) + * Motorola MVME187 (OpenBSD/mvme88k) PowerPC-based machines: - * IBM 6050/6070 (PReP, PowerPC Reference Platform) (NetBSD/prep) - * MacPPC (generic "G4" Macintosh) (NetBSD/macppc) * Artesyn PM/PPC (NetBSD/pmppc) + * IBM 6050/6070 (PReP, PowerPC Reference Platform) (NetBSD/prep) + * MacPPC (NetBSD/macppc, HelenOS/ppc) SuperH-based machines: + * Landisk I-O DATA USL-5P (NetBSD/landisk, OpenBSD/landisk) * Sega Dreamcast (NetBSD/dreamcast, Linux/dreamcast) - * Landisk I-O DATA USL-5P (OpenBSD/landisk) . Other machine types and architectures are emulated less completely. See the documentation in the gxemul-doc package for the exact details @@ -50,6 +53,7 @@ Section: doc Architecture: all Depends: ${misc:Depends} +Multi-Arch: foreign Description: gxemul documentation This package contains the documentation for gxemul, the machine emulator for multiple architectures. Among other things, instructions diff -Nru gxemul-0.6.2/debian/copyright gxemul-0.7.0+dfsg/debian/copyright --- gxemul-0.6.2/debian/copyright 2019-06-24 14:06:54.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/copyright 2021-11-27 09:42:41.000000000 +0000 @@ -2,9 +2,10 @@ Upstream-Name: GXemul Upstream-Contact: Anders Gavare Source: http://gavare.se/gxemul/ +Files-Excluded: test/FileLoader* Files: * -Copyright: 2003-2019 Anders Gavare +Copyright: 2003-2021, Anders Gavare License: BSD-3-clause Files: demos/* @@ -17,22 +18,25 @@ you can reuse the code even in projects which have licenses that are incompatible with the BSD-style licenses used for GXemul itself. -Files: doc/Doxyfile - doc/doxygen.css -Copyright: 1997-2015, Dimitri van Heesch -Comment: License extracted from the doxygen package -License: GPL with doxygen exception - Permission to use, copy, modify, and distribute this software and its - documentation under the terms of the GNU General Public License is hereby - granted. No representations are made about the suitability of this software - for any purpose. It is provided "as is" without express or implied warranty. - See the GNU General Public License for more details. - . - Documents produced by Doxygen are derivative works derived from the - input used in their production; they are not affected by this license. - . - On Debian systems, the complete text of the GNU General Public - License can be found in '/usr/share/common-licenses/GPL-2'. +Files: src/net/net_tap.c +Copyright: 2020, Jason R. Thorpe +License: BSD-3-clause + +Files: src/net/net_ether.c +Copyright: 2020, Jason R. Thorpe + 1982-1993, The Regents of the University of California +License: BSD-3-clause + +Files: src/include/thirdparty/bootblock.h +Copyright: 2002-2004, The NetBSD Foundation, Inc. + 1993, Allen K. Briggs + 1993, Chris P. Caputo, + 1993, Michael L. Finch + 1993, Bradley A. Grantham + 1993, Lawrence A. Kesteloot + 1994-1999, Christopher G. Demetriou + 1994, Rolf Grossmann +License: BSD-2-clause and BSD-4-clause Files: src/include/thirdparty/crmfbreg.h src/include/thirdparty/impactsr-bsd.h @@ -42,7 +46,7 @@ src/include/thirdparty/mvme_memcreg.h src/include/thirdparty/sh4_pcicreg.h Copyright: 2007, Jared D. McNeill - 1997, 1998, 2001, The NetBSD Foundation, Inc. + 1997-2001, The NetBSD Foundation, Inc. 1997, Manuel Bouyer 2008, Michael Lorenz 2005, NONAKA Kimihiro @@ -83,6 +87,13 @@ 1990, William Jolitz License: BSD-3-clause +Files: src/include/thirdparty/mb89352reg.h +Copyright: 1990-1993, The Regents of the University of California + 1996-1999, The NetBSD Foundation, Inc. + 1996-1998, NetBSD/pc98 porting staff + 1996-1998, Kouichi Matsuda +License: BSD-3-clause and BSD-2-clause + Files: src/include/thirdparty/adb_viareg.h src/include/thirdparty/algor_p5064reg.h src/include/thirdparty/arm_cputypes.h @@ -358,13 +369,6 @@ 2004, Miodrag Vallat. License: BSD-2-clause and cmu -Files: src/include/thirdparty/debug_new.h - src/include/thirdparty/fast_mutex.h - src/include/thirdparty/static_assert.h - src/main/debug_new.cc -Copyright: 2004-2005, Wu Yongwei -License: Zlib - Files: src/include/thirdparty/dc7085.h src/include/thirdparty/dec_prom.h src/include/thirdparty/lk201.h @@ -392,7 +396,7 @@ Copyright: 2003-2009, Anders Gavare License: BSD-2-clause -Files: src/promemul/dreamcast_scramble.cc +Files: src/promemul/dreamcast_scramble.c Copyright: Marcus Comstedt License: public-domain The sofware in this section is in the Public Domain. This means that @@ -423,7 +427,7 @@ | Yes, scramble.c is also in the public domain. Files: debian/* -Copyright: 2004-2019, Göran Weinholt +Copyright: 2004-2021, Göran Weinholt 2008-2010 Jonathan Wiltshire License: BSD-3-clause Comment: No explicit license historically; assuming 'LICENSE' applies diff -Nru gxemul-0.6.2/debian/gbp.conf gxemul-0.7.0+dfsg/debian/gbp.conf --- gxemul-0.6.2/debian/gbp.conf 2018-12-07 19:49:06.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/gbp.conf 2021-11-27 09:42:41.000000000 +0000 @@ -1,7 +1,7 @@ [DEFAULT] pristine-tar = True debian-branch = debian -upstream-tag = 'v%(version)s' +upstream-tag = v%(version)s [buildpackage] upstream-branch = upstream diff -Nru gxemul-0.6.2/debian/patches/remove_defines gxemul-0.7.0+dfsg/debian/patches/remove_defines --- gxemul-0.6.2/debian/patches/remove_defines 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/patches/remove_defines 2021-11-27 09:42:41.000000000 +0000 @@ -0,0 +1,116 @@ +From: =?utf-8?q?G=C3=B6ran_Weinholt?= +Date: Wed, 24 Nov 2021 20:57:00 +0100 +Subject: Upstream: "Removing weird defines, + hopefully enabling build on Linux." + +--- + doc/TODO.html | 4 ---- + src/include/thirdparty/bootblock.h | 11 ----------- + src/include/thirdparty/dp83932reg.h | 11 ----------- + src/include/thirdparty/pcireg.h | 11 ----------- + src/include/thirdparty/sgi_arcbios.h | 11 ----------- + 5 files changed, 48 deletions(-) + +diff --git a/doc/TODO.html b/doc/TODO.html +index da69628..25a34c8 100644 +--- a/doc/TODO.html ++++ b/doc/TODO.html +@@ -49,10 +49,6 @@ implement in GXemul. Some items in this list are perhaps already fixed. + e.g. verbosity disk debug <-- print all messages, but + breakpoint subsystem disk warn <-- break only for warn and error. + +-Build problems: +- o) Building a default build on my Linux machine currently fails with duplicate definitions from +- Linux' bits/socket.h being "extern inlined" twice? (configure --debug works fine though) +- + Misc.: + o) Try X11 grabbing with multiple host displays? ssh with X11 forwarding from laptop? + with multiple mouse pointers, _which_ mouse pointer is grabbed? +diff --git a/src/include/thirdparty/bootblock.h b/src/include/thirdparty/bootblock.h +index cf70798..cc2bf7a 100644 +--- a/src/include/thirdparty/bootblock.h ++++ b/src/include/thirdparty/bootblock.h +@@ -121,17 +121,6 @@ + #ifndef _SYS_BOOTBLOCK_H + #define _SYS_BOOTBLOCK_H + +-#ifdef __attribute__ +-#undef __attribute__ +-#endif +- +-#ifdef __noreturn__ +-#undef __noreturn__ +-#endif +- +-#define __attribute__(x) /* */ +-#define __noreturn__ /* */ +- + #if !defined(__ASSEMBLER__) + #if defined(_KERNEL) || defined(_STANDALONE) + #include +diff --git a/src/include/thirdparty/dp83932reg.h b/src/include/thirdparty/dp83932reg.h +index 06d9298..ed2f6e0 100644 +--- a/src/include/thirdparty/dp83932reg.h ++++ b/src/include/thirdparty/dp83932reg.h +@@ -4,17 +4,6 @@ + #ifndef _DEV_IC_DP83932REG_H_ + #define _DEV_IC_DP83932REG_H_ + +-#ifdef __attribute__ +-#undef __attribute__ +-#endif +- +-#ifdef __noreturn__ +-#undef __noreturn__ +-#endif +- +-#define __attribute__(x) /* */ +-#define __noreturn__ /* */ +- + /*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. +diff --git a/src/include/thirdparty/pcireg.h b/src/include/thirdparty/pcireg.h +index 162a516..1c2007e 100644 +--- a/src/include/thirdparty/pcireg.h ++++ b/src/include/thirdparty/pcireg.h +@@ -4,17 +4,6 @@ + #ifndef _DEV_PCI_PCIREG_H_ + #define _DEV_PCI_PCIREG_H_ + +-#ifdef __attribute__ +-#undef __attribute__ +-#endif +- +-#ifdef __noreturn__ +-#undef __noreturn__ +-#endif +- +-#define __attribute__(x) /* */ +-#define __noreturn__ /* */ +- + /* + * Copyright (c) 1995, 1996, 1999, 2000 + * Christopher G. Demetriou. All rights reserved. +diff --git a/src/include/thirdparty/sgi_arcbios.h b/src/include/thirdparty/sgi_arcbios.h +index ccd4df3..51f3e38 100644 +--- a/src/include/thirdparty/sgi_arcbios.h ++++ b/src/include/thirdparty/sgi_arcbios.h +@@ -6,17 +6,6 @@ + + /* It's better to not #define sgimips here, and assume generic ARC instead */ + +-#ifdef __attribute__ +-#undef __attribute__ +-#endif +- +-#ifdef __noreturn__ +-#undef __noreturn__ +-#endif +- +-#define __attribute__(x) /* */ +-#define __noreturn__ /* */ +- + /* $NetBSD: arcbios.h,v 1.3 2001/12/06 14:59:02 rafal Exp $ */ + + /*- diff -Nru gxemul-0.6.2/debian/patches/series gxemul-0.7.0+dfsg/debian/patches/series --- gxemul-0.6.2/debian/patches/series 2018-12-07 19:50:49.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/patches/series 2021-11-27 09:42:41.000000000 +0000 @@ -0,0 +1 @@ +remove_defines diff -Nru gxemul-0.6.2/debian/rules gxemul-0.7.0+dfsg/debian/rules --- gxemul-0.6.2/debian/rules 2019-06-24 20:22:50.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/rules 2021-11-27 12:15:24.000000000 +0000 @@ -1,18 +1,26 @@ #!/usr/bin/make -f # debian/rules for gxemul. +include /usr/share/dpkg/architecture.mk +include /usr/share/dpkg/pkg-info.mk -#export DH_VERBOSE=1 - -CFLAGS = -g - -ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CFLAGS += -O0 +ifeq ($(origin CC),default) +CC := $(DEB_HOST_GNU_TYPE)-gcc endif override_dh_auto_configure: - CFLAGS="${CFLAGS}" PREFIX="/usr" DESTDIR=$(shell pwd)/debian/tmp ./configure --disable-valgrind + CFLAGS="${CFLAGS}" PREFIX="/usr" DESTDIR=$(shell pwd)/debian/tmp ./configure + sed -e 's/#define VERSION.*/#define VERSION \"$(DEB_VERSION_UPSTREAM)\"/g' \ + -e 's/#define COMPILE_DATE.*/#define COMPILE_DATE "compiled by Debian"/' \ + -i config.h + sed -e 's/-Wl,-rpath,[^\w]*//g' -i Makefile touch configure-stamp +override_dh_auto_build: + make -C src/include + make -C src/devices/fonts Xconv_raw_to_c + make -C src/cpus generate_head generate_tail $(shell awk '/^CPU_TOOLS/{$$1="";print}' src/cpus/Makefile) + dh_auto_build -- CC="${CC}" + override_dh_install: dh_install rm -rf debian/gxemul/usr/share/doc/gxemul/* diff -Nru gxemul-0.6.2/debian/watch gxemul-0.7.0+dfsg/debian/watch --- gxemul-0.6.2/debian/watch 2018-12-07 17:45:39.000000000 +0000 +++ gxemul-0.7.0+dfsg/debian/watch 2021-11-27 10:06:31.000000000 +0000 @@ -1,2 +1,3 @@ -version=3 -http://gavare.se/gxemul/src/gxemul-(\d+\..+)\.tar\.gz +version=4 +opts=dversionmangle=auto,repacksuffix=+dfsg \ + http://gavare.se/gxemul/src/gxemul-(\d+\..+)\.tar\.gz Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20190715-sgi-o2-linux.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20190715-sgi-o2-linux.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20190715-sgi-o2-linux-small.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20190715-sgi-o2-linux-small.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20210222-openbsd-luna88k-mp-1.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20210222-openbsd-luna88k-mp-1.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20210222-openbsd-luna88k-mp-1-small.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20210222-openbsd-luna88k-mp-1-small.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20210222-openbsd-luna88k-mp-2.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20210222-openbsd-luna88k-mp-2.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20210222-openbsd-luna88k-mp-2-small.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20210222-openbsd-luna88k-mp-2-small.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20210328-openbsd-luna88k-inside-openbsd-luna88k.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20210328-openbsd-luna88k-inside-openbsd-luna88k.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/20210328-openbsd-luna88k-inside-openbsd-luna88k-small.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/20210328-openbsd-luna88k-inside-openbsd-luna88k-small.png differ diff -Nru gxemul-0.6.2/doc/components/component_cache.html gxemul-0.7.0+dfsg/doc/components/component_cache.html --- gxemul-0.6.2/doc/components/component_cache.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/components/component_cache.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,34 +0,0 @@ - - - - - GXemul: Components: cache - - - - - - -

GXemul: Components: cache

-

- -Back to the index. -

Back to the component index. - - -


cache component

- -The cache component represents a memory cache. Caches are usually -connected to CPUs, between the CPU and main memory. - -

TODO. - - -

Source code for this component can be found -here -(and Doxygen documentation -here). - -



- - diff -Nru gxemul-0.6.2/doc/components/component_cpu.html gxemul-0.7.0+dfsg/doc/components/component_cpu.html --- gxemul-0.6.2/doc/components/component_cpu.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/components/component_cpu.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ - - - - - GXemul: Components: cpu - - - - - - -

GXemul: Components: cpu

-

- -Back to the index. -

Back to the component index. - - -


cpu component

- -This is a base class for CPU components. - -

Examples of CPUs include: -

- -

Source code for this component can be found -here -(and Doxygen documentation -here). - -



- - diff -Nru gxemul-0.6.2/doc/components/component_dummy.html gxemul-0.7.0+dfsg/doc/components/component_dummy.html --- gxemul-0.6.2/doc/components/component_dummy.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/components/component_dummy.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - - - - - GXemul: Components: dummy - - - - - - -

GXemul: Components: dummy

-

- -Back to the index. -

Back to the component index. - - -


dummy component

- -The dummy component does not do anything. It can contain -any other components. It is also used for the emulator's internal -unit tests. - - -

-Source code documentation for this component can be found -here. - -



- - diff -Nru gxemul-0.6.2/doc/components/component_i960_cpu.html gxemul-0.7.0+dfsg/doc/components/component_i960_cpu.html --- gxemul-0.6.2/doc/components/component_i960_cpu.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/components/component_i960_cpu.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ - - - - - GXemul: Components: i960_cpu - - - - - - -

GXemul: Components: i960_cpu

-

- -Back to the index. -

Back to the component index. - - -


i960_cpu component

- -This component represents an -Intel i960-like -CPU component. - -

Things that have been implemented: - -

    -
  • i960 Cx disassembly. -
- -

Things that have not yet been implemented: TODOs in approximate priority order: - -

    -
  • Disassembly of instructions for variants other than i960 CA / CF. -
  • Implement register dump functionality better (specifics about - SFRs, AC/PC/TC flags etc). -
  • b.out file loader: symbol support. (Not in the CPU component but related.) -
  • ECOFF file loader. (Not in the CPU component but related.) -
  • Start implementing execution of instructions. -
  • Implement some kind of "short diff" format for execution, - rather than the verbose format of today. -
- - -

-Source code documentation for this component can be found -here. - -



- - diff -Nru gxemul-0.6.2/doc/components/component_m88k_cpu.html gxemul-0.7.0+dfsg/doc/components/component_m88k_cpu.html --- gxemul-0.6.2/doc/components/component_m88k_cpu.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/components/component_m88k_cpu.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ - - - - - GXemul: Components: m88k_cpu - - - - - - -

GXemul: Components: m88k_cpu

-

- -Back to the index. -

Back to the component index. - - -


m88k_cpu component

- -This component represents a -Motorola 88000-like -CPU component. - -

Features that have been implemented: - -

    -
  • 88100 disassembly. -
- -

TODO: Almost everything. - - -

-Source code documentation for this component can be found -here. - -



- - diff -Nru gxemul-0.6.2/doc/components/component_mainbus.html gxemul-0.7.0+dfsg/doc/components/component_mainbus.html --- gxemul-0.6.2/doc/components/component_mainbus.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/components/component_mainbus.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ - - - - - GXemul: Components: mainbus - - - - - - -

GXemul: Components: mainbus

-

- -Back to the index. -

Back to the component index. - - -


mainbus component

- -The mainbus component forwards address/data requests from -e.g. CPUs to memory mapped components. -A typical example of a memory mapped component is RAM. - -

Source code for this component can be found -here -(and Doxygen documentation -here). - -



- - diff -Nru gxemul-0.6.2/doc/components/component_ram.html gxemul-0.7.0+dfsg/doc/components/component_ram.html --- gxemul-0.6.2/doc/components/component_ram.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/components/component_ram.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ - - - - - GXemul: Components: ram - - - - - - -

GXemul: Components: ram

-

- -Back to the index. -

Back to the component index. - - -


ram component

- -The ram component represents a Random Access Memory. - -

Note that also ROM (Read-Only Memory) circuits are emulated using this -component. A ROM circuit is a RAM with writeProtect = true. - -

The following example shows how to interactively add a ram -component to a machine: - -

-$ gxemul -V
-..
-GXemul> add machine
-GXemul> add mainbus machine0
-GXemul> root
-  root
-  \-- machine0
-      \-- mainbus0
-
-  accuracy = cycle
-  step     = 0
-GXemul> add ram mainbus0
-GXemul> ram
-  ram0  (0 bytes at offset 0)
-
-  data                = (custom)
-  lastDumpAddr        = 0
-  memoryMappedAddrMul = 0x1
-  memoryMappedBase    = 0
-  memoryMappedSize    = 0
-  step                = 0
-  writeProtect        = false
-GXemul> ram0.memoryMappedSize = 0x400000
-GXemul> root
-  root
-  \-- machine0
-      \-- mainbus0
-          \-- ram0  (4 MB at offset 0)
-
-  accuracy = cycle
-  step     = 0
-GXemul> 
-
- -

Source code for this component can be found -here -(and Doxygen documentation -here). - -



- - diff -Nru gxemul-0.6.2/doc/configfiles.html gxemul-0.7.0+dfsg/doc/configfiles.html --- gxemul-0.6.2/doc/configfiles.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/configfiles.html 2021-11-27 09:42:23.000000000 +0000 @@ -16,7 +16,7 @@ - diff -Nru gxemul-0.6.2/doc/experiments.html gxemul-0.7.0+dfsg/doc/experiments.html --- gxemul-0.6.2/doc/experiments.html 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/experiments.html 2021-11-27 09:42:23.000000000 +0000 @@ -111,7 +111,7 @@ Run gxemul -H for an up-to-date list. -

Here are some examples of guest OSes that run in the test machine modes: +

Here are some examples of guest OSes that use or (have used) the test machine modes:

@@ -147,13 +163,36 @@ + ram: +

The first 256 MB of RAM. +
Physical address:  0x00000000 + +   + + + + + + + + +
Comment:
+ + + + +   + + + + cons:

A simple console device, for writing characters to the controlling terminal and receiving keypresses.

Source code:  src/devices/dev_cons.c

Include file:  dev_cons.h -
Default physical address:  0x10000000 +
Physical address:  0x10000000   @@ -189,7 +228,7 @@ multi-processor system.

Source code:  src/devices/dev_mp.c

Include file:  dev_mp.h -
Default physical address:  0x11000000 +
Physical address:  0x11000000 @@ -291,10 +330,11 @@ fb:

A simple linear framebuffer, for graphics output. - 640 x 480 pixels, 3 bytes per pixel (red, green, blue, 8 bits each). + Initial resolution is 640 x 480 pixels, with 3 bytes per pixel + (red, green, blue, 8 bits each).

Source code:  src/devices/dev_fb.c

Include file:  dev_fb.h -
Default physical address:  0x12000000 +
Physical address:  0x12000000 @@ -304,9 +344,17 @@ Effect: - 0x00000-
0xe0fff + 0x00000000      Read: read pixel values. -
Write: write pixel values. + Write: write pixel values. + + + 0x00f00000      + Read/Write: Control ports for changing the + resolution at runtime, etc. See dev_fb.h and + dev_fbctrl.cc for more details. +

If the resolution is read back as X=0 Y=0, then that + means that graphics is not used, only serial console. @@ -324,7 +372,7 @@ write operations finish instantaneously.

Source code:  src/devices/dev_disk.c

Include file:  dev_disk.h -
Default physical address:  0x13000000 +
Physical address:  0x13000000 @@ -378,7 +426,7 @@ and receive packets on a simulated network.

Source code:  src/devices/dev_ether.c

Include file:  dev_ether.h -
Default physical address:  0x14000000 +
Physical address:  0x14000000 @@ -432,7 +480,7 @@ and to cause periodic interrupts.

Source code:  src/devices/dev_rtc.c

Include file:  dev_rtc.h -
Default physical address:  0x15000000 +
Physical address:  0x15000000 @@ -479,7 +527,7 @@

An Interrupt Controller. (Note: Not used for the MIPS test machine.)

Source code:  src/devices/dev_irqc.c

Include file:  dev_irqc.h -
Default physical address:  0x16000000 +
Physical address:  0x16000000 @@ -522,9 +570,9 @@

If the physical address is 0x10000000, then for MIPS that means that it can be accessed at virtual address -0xffffffffb0000000. (Actually it can be accessed at -0xffffffff90000000 too, but devices should usually be accessed in -a non-cached manner.) +0xffffffffb0000000. (Using virtual address +0xffffffff90000000 may work in the emulator, but should be +avoided, since devices should in general be accessed in a non-cached manner.)

When using the ARM or PPC test machines, the addresses are 0x10000000, 0x11000000 etc., so no need to add any diff -Nru gxemul-0.6.2/doc/framework.html gxemul-0.7.0+dfsg/doc/framework.html --- gxemul-0.6.2/doc/framework.html 2019-06-22 18:23:29.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/framework.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,280 +0,0 @@ - - - - - GXemul: Description of the framework - - - - - - -

GXemul: Description of the framework

-

- -Back to the index. - - - -


-

- - - -


- -

Introduction:

- -

Starting with GXemul 0.6.x, a completely redesigned framework is being -worked on, compared to the 0.4.x series. The emulator thus contains two -completely different frameworks. -This chapter of the documentation describes the core concepts of the -new framework. The framework is still being designed and -implemented, so -what you are reading can be considered an early draft, or a work-in-progress. - -

Almost all of the emulation modes in GXemul are implemented using the -earlier (pre-0.6) framework, but newly implemented emulation modes may -use the new framework instead. - - - - -


- -

Components:

- -

The most important concept in the new framework is that of the -component. A component can have sub-components -(children) and a parent, so the components make up a configuration tree: - -

- -

Component classes are registered in a component registry. - -

Each component in the emulation setup has a path, e.g. -root.machine1.mainbus0.cpu0 for the -CPU in the right-most machine in the example above. Often, shorter paths can -be used, such as machine1 instead of root.machine1, if there -is no ambiguity. - -

Each component has state, which is a collection of variables. -For e.g. a CPU component, the state is usually a set of registers. Each component -also has a set of methods which can be executed. A CPU may disassemble -instructions using its unassemble method: - -

 
-GXemul> root
-  root
-  \-- machine0  [testm88k]
-      \-- mainbus0
-          |-- cpu0  (88100, 50 MHz)
-          |-- ram0  (32 MB at offset 0)
-          |-- fb_videoram0  (15 MB at offset 0x12000000)
-          \-- rom0  (4 MB at offset 0xff800000)
-
-  accuracy = cycle
-  step     = 0
-GXemul> cpu0.unassemble
-<_f>
-0x12b8 <- 67ff0020   subu    r31,r31,0x20 
-0x12bc    27df0010   st      r30,r31,0x10 
-0x12c0    63df0010   addu    r30,r31,0x10 
-0x12c4    58400320   or      r2,r0,0x320  
-0x12c8    58600258   or      r3,r0,0x258  
-0x12cc    243f0014   st      r1,r31,0x14  
-0x12d0    231f0008   st.d    r24,r31,0x8  
-0x12d4    cfffffe7   bsr.n   0x1270          ; <_change_resolution>
-0x12d8    f6c0201f   st.d    r22,r0,r31   
-0x12dc    cbffff89   bsr     0x1100          ; <_my_random>        
-0x12e0    f6c05802   or      r22,r0,r2    
-...
-
- -

When single-stepping, all state change is displayed. (In the old framework, -it was up to individual device/component implementations to print debug -messages.) - -

 
-GXemul> step
-step 0: cpu0: <_f>
-              0x12b8    67ff0020   subu   r31,r31,0x20
-        => cpu0.pc: 0x12b8 -> 0x12bc
-        => cpu0.r31: 0xff0 -> 0xfd0
-GXemul> 
-step 1: cpu0: 0x12bc    27df0010   st   r30,r31,0x10
-        => cpu0.pc: 0x12bc -> 0x12c0
-GXemul> 
-
- -

The example above may not be that interesting, but imagine that the CPU -reads from a device which has a zero-on-read status register. Then the -output may look something like this: (this is a made-up example, for now) - -

 
-GXemul> step
-step 2: cpu0: 0xffffffff800101f4    12345678   lw   t3,256(a1)
-        => cpu0.pc: 0xffffffff800101f4 -> 0xffffffff800101f8
-        => cpu0.t3: 0 -> 0x2200
-        => intcontroller.status: 0x2200 -> 0
-GXemul> 
-
- -

Components that have a frequency are executed in steps. Those that -do not have a frequency only do things if triggered by some other means (i.e. -another component). The components' relative frequencies determine how many -steps they will run at a time. For example, if we have component A running at -100 MHz, and component B running at 1 MHz, then in 100 steps A will be executing -100 cycles and B only 1. The GXemul framework makes sure that the exact sequence -of cycles is the same nomatter if the user is single-stepping, or running -the simulation continuously. - -

The frequency mentioned above does not have anything at all to do with how -fast a particular host executes the simulation. The frequencies are only relative -to each other. - -

Is the new framework cycle-accurate? Both yes and no. The framework -itself aims to be step accurate, but it is up to the implementation of -individual components to also be cycle accurate. For example, -the CPU components that are available out-of-the-box in GXemul do not -try to simulate out-of-order execution, or pipe-line stalls, or other -effects that happen in a real processor, so even though the aim is that the -implementation should be cycle accurate, it does not simulate -any existing real-world processor in a cycle-accurate manner. - -

Is it theoretically possible to implement pipe-lined and/or -out-of-order CPU models for GXemul's new framework? Maybe. But that has not been done. - -

Note that the component framework described on this page should not be -confused with the dyntrans mechanism (sometimes -referred to as "the dyntrans framework"). The dyntrans framework is a helper -mechanism (or, to use C++ terminology, a base class) for implementing specific CPUs. - - - - - - -


- -

Machine templates:

- -

Although the framework is generic enough to simulate/emulate many kinds of -components, the focus is on emulating components found in electronic computers, -such as processors, RAM, caches, graphics cards, etc. In most cases, these -components are naturally contained in a machine. - -

Machines are registered in a machine registry. The end-user can list -the available machines in the registry by running gxemul -H (or by -reading the documentation built by make documentation). - -

In the older framework, machines were a special type of entity in the emulator, -which held one or more CPUs of a particular architecture, e.g. -MIPS. In fact, -the entire machine was of that architecture. The machine also had hardcoded RAM. -While this worked well, it was not generic enough to support some cases that -occur in the real world: -

    -
  • Processors of different architectures in the same machine. An - example of this is the Dreamcast, - which has an SH4 main - CPU, and an ARM CPU as a sound processor. Other examples - could be GPUs in modern workstations being considered as CPUs. -
  • Hardcoded RAM required hacks for those architectures that do not - have RAM at offset 0, for example some SGI machines, or - the Dreamcast. -
- -

The 0.6.0 framework, however, has a somewhat generalized view of what a machine -is. Machines are simply templates for how components are configured. -When adding such a template machine to the configuration tree, the result -is a complete tree of components: -

-	GXemul> add testm88k
-	GXemul> root
-	  root
-	  \-- machine0  [testm88k]
-	      \-- mainbus0
-	          |-- cpu0  (88100, 50 MHz)
-	          |-- ram0  (32 MB at offset 0)
-	          |-- fb_videoram0  (15 MB at offset 0x12000000)
-	          \-- rom0  (4 MB at offset 0xff800000)
-
- -

-Here, a testm88k machine template was added (to the root -component). Adding something without specifying where to add it always assumes -that the root component is the target. The name of the machine in the -component tree is root.machine0. The tree dump shows that it was created using the -testm88k template. - -

To make it easier to start a new emulation from the command line (and to be -more or less backward compatible with pre-0.6.x command line syntax), the --e option can be used to start an emulation based on a template machine: -

-	$ ./gxemul -V -e testm88k
-	GXemul (unknown version)      Copyright (C) 2003-2019  Anders Gavare
-
-	  mainbus0
-	  |-- cpu0  (88100, 50 MHz)
-	  |-- ram0  (32 MB at offset 0)
-	  |-- fb_videoram0  (15 MB at offset 0x12000000)
-	  \-- rom0  (4 MB at offset 0xff800000)
-
-	GXemul> 
-
- -

(When starting a single emulated machine from the command line, only the emulated machine is shown, -not the entire tree from the root node.) - -

The same machine configuration can be set up by hand as well: - -

-	GXemul> add machine root
-	GXemul> add mainbus machine0
-	GXemul> add ram mainbus0
-	GXemul> ram0.memoryMappedSize = 0x2000000
-	GXemul> add m88k_cpu mainbus0
-	GXemul> root
-	  root
-	  \-- machine0
-	      \-- mainbus0
-	          |-- ram0  (32 MB at offset 0)
-	          \-- cpu0  (88100, 50 MHz)
-
- -

(Omitting rom0 and fb_videoram0 for brevity.) - - - diff -Nru gxemul-0.6.2/doc/head.html gxemul-0.7.0+dfsg/doc/head.html --- gxemul-0.6.2/doc/head.html 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/head.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ - - - - - GXemul: PAGETITLE - - - - - - -

GXemul: PAGETITLE

-

- -Back to the index. - - - -


- diff -Nru gxemul-0.6.2/doc/index.html gxemul-0.7.0+dfsg/doc/index.html --- gxemul-0.6.2/doc/index.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/index.html 2021-11-27 09:42:23.000000000 +0000 @@ -14,7 +14,7 @@ -

These instructions are here mostly for me to remember how to debug/proceed: +

+ + + + +

The last of the screenshots above shows the OpenBSD/luna88k kernel booting +inside GXemul, compiled inside emulated OpenBSD/luna88k running in GXemul on +a FreeBSD/amd64 host. -

-Download a RAMDISK kernel: +

There are a couple of ways to run and/or install OpenBSD in the emulator. +

-

For 5.4 and below: + + +


+ +

OpenBSD/luna88k from a "live" harddisk image:

+ +

Kenji Aoyama has made available full harddisk images from a real +OpenBSD installation. Download the latest such harddisk image and +boot program from +http://www.nk-home.net/~aoyama/liveimage/, +and start the emulator like this: + +

-	gxemul -e luna-88k 0x20000:0x20:bsd.rd
+	gxemul -e luna-88k -d liveimage-luna88k-raw-20201206.img boot
 
-

or for the newer ones: +

To run with a graphical framebuffer, add -X to the command line. -

-	gxemul -e luna-88k bsd.rd
+

To shut down the machine gracefully, run reboot as root. + + + + +


+ +

OpenBSD/luna88k network installation:

+ +

To install OpenBSD, you first need to create an empty harddisk image +onto which the operating system will be installed: + +

+	dd if=/dev/zero of=obsd_luna88k.img bs=1024 count=1 seek=5500000
 
-

From 6.0 and newer, bugs are triggered (most likely in GXemul): +

Then download the ramdisk kernel, a regular kernel, and the boot program: +

+ +

Start the emulator like this, and install as if you were doing a network +(http) install on a real machine:

-	panic: amap_wipeout: corrupt amap
+	gxemul -e luna-88k -d obsd_luna88k.img bsd.rd
 
-

The 5.9 kernel gets further than 6.0 (reaching userland) when run without graphical framebuffer: +

For networking configuration, enter IPv4 address 10.0.0.1, netmask 255.0.0.0, +and skip IPv6 configuration. Default route and DNS nameserver should both be 10.0.0.254. -

-CPU0 is associated to 2 MC88200 CMMUs
-CPU1 is associated to 2 MC88200 CMMUs
-CPU2 is associated to 2 MC88200 CMMUs
-CPU3 is associated to 2 MC88200 CMMUs
-Copyright (c) 1982, 1986, 1989, 1991, 1993
-	The Regents of the University of California.  All rights reserved.
-Copyright (c) 1995-2016 OpenBSD. All rights reserved.  http://www.OpenBSD.org
-
-OpenBSD 5.9 (RAMDISK) #0: Fri Mar  4 23:48:03 JST 2016
-    aoyama@rhea.in.nk-home.net:/w1/o/5.9/src/sys/arch/luna88k/compile/RAMDISK
-real mem = 117440512 (112MB)
-avail mem = 110456832 (105MB)
-mainbus0 at root: OMRON LUNA-88K, 25MHz
-cpu0: M88100 rev 0x3, 2 CMMU
-cpu0: M88200 (16K) rev 0x9, full Icache
-cpu0: M88200 (16K) rev 0x9, full Dcache
-clock0 at mainbus0: MK48T02
-le0 at mainbus0: address 00:00:00:00:00:00
-le0: 32 receive buffers, 8 transmit buffers
-sio0 at mainbus0: 7201a
-siotty0 at sio0 channel 0 (console)
-ws0 at sio0 channel 1[ luna88k sio dev1 write data: TODO ]
-
-wskbd0 at ws0
-fb at mainbus0 not configured
-spc0 at mainbus0
-scsibus0 at spc0: 8 targets, initiator 7
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-spc0: SCSI bus reset
-boot device: <unknown>
-root on rd0a swap on rd0b dump on rd0b
-WARNING: clock lost 281 days -- CHECK AND RESET THE DATE!
-erase ^?, werase ^W, kill ^U, intr ^C, status ^T
-
-Welcome to the OpenBSD/luna88k 5.9 installation program.
-(I)nstall, (U)pgrade, (A)utoinstall or (S)hell? s
-# echo $OBSD
-OpenBSD/luna88k 5.9
-# 
-
- -

It seems that some versions of OpenBSD had a tiny bug in the framebuffer -scroll up routine, so it does not contain any loads or stores. - -

Using a breakpoint --p om1_windowmove in both OpenBSD 5.9 and 6.2 indicates that -5.9 must have been optimized too heavily or had a bug; it loops when trying to copy -pixels to scroll up the text, but the loop contains "nothing": +

NOTE: Doing a network install is currently really really slow. +It is so slow that it will probably say "stalled" in the download progress +reporting, but just leave it on and eventually it will have downloaded +everything. +

Finally, once the installation finishes, reboot the emulated machine and +start again using either the boot loader, or using the regular kernel:

-s001553b8: 64e70001	subu	r7,r7,1
-s001553bc: 61270001	addu	r9,r7,1
-s001553c0: ec4c0004	bcnd.n	eq0,r12,0x001553d0	; <om1_windowmove+0x3b0>
-s001553c4: 59600000 (d)	or	r11,r0,0x0
-s001553c8: f1a08832	set	r13,r0,1<18>
-s001553cc: f562600d	addu	r11,r2,r13
-s001553d0: 60420004	addu	r2,r2,4
-s001553d4: eda9fff9	bcnd.n	ne0,r9,0x001553b8	; <om1_windowmove+0x398>
-s001553d8: 616b0004 (d)	addu	r11,r11,4
-s001553b8: 64e70001	subu	r7,r7,1
-...
+	gxemul -e luna-88k -d obsd_luna88k.img boot
+
+	or
+
+	gxemul -e luna-88k -d obsd_luna88k.img bsd
 
-

compared to what it looks like in 6.2: +

Using the boot loader mimics how a real machine would start up OpenBSD +on the luna88k. Using the regular kernel has the advantage that it includes +symbols, which are useful when debugging the kernel. + +

To run with a graphical framebuffer, add -X to the command line. + +

To shut down the machine gracefully, run reboot as root. + + + + +


+ +

OpenBSD/luna88k with root-on-nfs:

+ +

Back when GXemul did not emulate the SCSI controller in the LUNA88K machine, +the only way to run OpenBSD/luna88k was using root-on-nfs. These instructions +can still be used, if you want to do it that way. + +

+Another emulated machine must then be used as the nfs root server, and the +emulated LUNA88K machine must boot as a diskless +client. To make matters even more complicated, the OpenBSD/luna88k 6.8 RAMDISK +kernel has support for Ethernet, but it does not seem to have a driver for +nfs included or at least it doesn't work in the emulator. Therefore, a separate +OpenBSD ramdisk kernel, e.g. for OpenBSD/sgi, needs to be used to run the final +step of the root-on-nfs installation. + +

Let's get started. + +

+

    +
  1. First of all, the "nfs server" machine must be set up. + Install NetBSD/pmax 8.0 from CDROM, + perform a default install (without X11) from CDROM without configuring the + network, but add a 4000 MB /tftpboot partition when + configuring the disk! +

    +

  2. On the host, download the OpenBSD distribution: +

           
    wget http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/base68.tgz
    +wget http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/comp68.tgz
    +wget http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/xbase68.tgz
    +wget http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/xfont68.tgz
    +wget http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/xserv68.tgz
    +wget http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/xshare68.tgz
    +
    +

  3. Start the emulation of the DECstation NFS server using this command line: +

           
    gxemul -xe 3max -d nbsd_pmax.img -d base68.tgz -d comp68.tgz -d xbase68.tgz -d xfont68.tgz -d xserv68.tgz -d xshare68.tgz
    +
    +and enter the following commands to configure the server for NFS serving and +extract the OpenBSD distribution: +
           
    +echo hostname=server >> /etc/rc.conf
    +echo ifconfig_le0=\"inet 10.0.0.2\" >> /etc/rc.conf
    +echo nameserver 10.0.0.254 >> /etc/resolv.conf
    +echo 10.0.0.254 > /etc/mygate
    +echo /tftpboot -maproot=root -alldirs 10.0.0.3 > /etc/exports
    +echo rpcbind=YES >> /etc/rc.conf
    +echo nfs_server=YES >> /etc/rc.conf
    +echo mountd=YES >> /etc/rc.conf
    +echo bootparamd=YES >> /etc/rc.conf
    +printf "client root=10.0.0.2:/tftpboot swap=10.0.0.2:/tftpboot/swap\n" > /etc/bootparams
    +echo "00:00:0a:10:20:30 client" > /etc/ethers
    +echo 10.0.0.3 client > /etc/hosts
    +
    +cd /tftpboot
    +tar xzf /dev/sd1c
    +tar xzf /dev/sd2c
    +tar xzf /dev/sd3c
    +tar xzf /dev/sd4c
    +tar xzf /dev/sd5c
    +tar xzf /dev/sd6c
    +
    +tar zxfv var/sysmerge/etc.tgz
    +tar zxfv var/sysmerge/xetc.tgz
    +
    +chmod 1777 tmp
    +
    +dd if=/dev/zero of=swap bs=1024 count=262144
    +
    +echo inet 10.0.0.3 > /tftpboot/etc/hostname.le0
    +chmod 640 /tftpboot/etc/hostname.le0
    +echo 10.0.0.254 > /tftpboot/etc/mygate
    +echo nameserver 10.0.0.254 > /tftpboot/etc/resolv.conf
    +echo 127.0.0.1 client localhost > /tftpboot/etc/hosts
    +
    +echo 10.0.0.2:/tftpboot / nfs rw 0 0 > /tftpboot/etc/fstab
    +echo 10.0.0.2:/tftpboot/swap none swap sw,nfsmntpt=/swap >> /tftpboot/etc/fstab
    +
    +halt
    +
    +

  4. Download the OpenBSD/luna88k GENERIC, MULTIPROCESSOR, and RAMDISK kernels:
    +	http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/bsd
    +	http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/bsd.mp
    +	http://ftp.eu.openbsd.org/pub/OpenBSD/6.8/luna88k/bsd.rd
     
    -
    -s001547a4: 64e70001	subu	r7,r7,1
    -s001547a8: 61270001	addu	r9,r7,1
    -s001547ac: 60420004	addu	r2,r2,4
    -s001547b0: eda9fffa	bcnd.n	ne0,r9,0x00154798	; <om1_windowmove+0x398>
    -s001547b4: 616b0004 (d)	addu	r11,r11,4
    -s00154798: edac003e	bcnd.n	ne0,r12,0x00154890	; <om1_windowmove+0x490>
    -s0015479c: f1208832 (d)	set	r9,r0,1<18>
    -s00154890: f5021409	ld	r8,r2,r9	; [0xb10c958c]
    -s00154894: c7ffffc4	br.n	0x001547a4	; <om1_windowmove+0x3a4>
    -s00154898: f500240b (d)	st	r8,r0,r11	; [0xb1087f8c]
    -s001547a4: 64e70001	subu	r7,r7,1
     
    +
  5. Create a configuration file called config_client: +
           
    +!  Configuration file for running OpenBSD/luna88k diskless with
    +!  a NetBSD/pmax machine as the nfs server.
    +!
    +!  This config file is for the client.
    +
    +net(
    +	add_remote("localhost:12444")   ! the server
    +	local_port(12445)               ! the client
    +)
    +
    +machine(
    +	name("client machine")
    +	serial_nr(1)
    +
    +        type("luna88k")
    +        subtype("luna-88k")
    +	! use_x11(1)
    +
    +	! For multiprocessor experiments:
    +	! ncpus(4)
    +        ! load("bsd.mp")
    +
    +        ! load("bsd.rd")
    +        load("bsd")
    +)
    +
    +
    + ... and another configuration file for the server, + config_server: +
           
    +net(
    +	local_port(12444)               ! the server
    +	add_remote("localhost:12445")   ! the client
    +)
    +
    +machine(
    +	name("nfs server")
    +	serial_nr(2)
    +
    +        type("dec")
    +        subtype("5000/200")
    +
    +        disk("nbsd_pmax.img")
    +)
    +
    +
    -

    Note the actual loads and stores to video ram (0xb10.....). +

  6. Download an OpenBSD/sgi RAMDISK kernel (only used to run MAKEDEV):
    +	http://ftp.eu.openbsd.org/pub/OpenBSD/6.7/sgi/bsd.rd.IP32
     
    -

    Going back all the way to an old 5.4 kernel allows the framebuffer to -be used: -

    -	gxemul -X -e luna-88k 0x20000:0x20:bsd.rd
     
    -

    - +

  7. Create a configuration file called config_client_sgi: +
           
    +!  Configuration file for running OpenBSD/sgi diskless with
    +!  a NetBSD/pmax machine as the nfs server.
    +!
    +!  This config file is for the client.
    +
    +net(
    +	add_remote("localhost:12444")   ! the server
    +	local_port(12445)               ! the client
    +)
    +
    +machine(
    +	name("client machine")
    +	serial_nr(1)
    +
    +        type("sgi")
    +        subtype("o2")
    +	use_x11(1)
    +	memory(1024)
    +
    +        load("bsd.rd.IP32")
    +        ! load("bsd.IP32")
    +)
    +
    +
    + +
  8. Boot the "nfs server" and the OpenBSD/sgi + "client machine" as two separate emulator instances:
    +	in one xterm:
    +	gxemul @config_server
     
    +	and then, in another xterm:
    +	gxemul @config_client_sgi
     
    -

    The following is not needed in order to experiment with booting OpenBSD, -but can be interesting nonetheless: Download -https://ftp.eu.openbsd.org/pub/OpenBSD/6.2/luna88k/boot and try +

    + +
  9. In the emulated OpenBSD/sgi client, type 's' for Shell and run these commands: +
           
    +ifconfig mec0 10.0.0.3; route add default 10.0.0.254
    +mount -v 10.0.0.2:/tftpboot /mnt
    +cd /mnt/dev; ./MAKEDEV all; cd /; umount /mnt
    +halt -p
    +
    +
  10. Finally, run the luna88k client:
    +	gxemul @config_client
     
    -
    -	gxemul -v -e luna-88k 0x00700000:0x20:0x00700000:boot
     
    + When asked about root device, enter le0. +
+ + +


+If you want to run with the graphical framebuffer, uncomment the +use_x11(1) line in config_client first. +Unfortunately, Xorg lacks a driver for wsfb in OpenBSD/luna88k +6.8, which is needed. + +

You can extract the files +

./usr/X11R6/lib/modules/drivers/wsfb_drv.la
+./usr/X11R6/lib/modules/drivers/wsfb_drv.so
+
+

from the OpenBSD +6.7 xserver distribution file, and use them even if the +rest of the OS is version 6.8. If you have extracted the files above, +then start X by running startx.


+ +

OpenBSD/luna88k MultiProcessor experiments:

+ +

You can experiment with the multiprocessor kernel (bsd.mp), with up to +4 emulated CPUs. It is not as stable as running single-processor, though. +Also, the emulator itself is not multithreaded, so all CPUs are emulated +using a single host processor, so a higher number of emulated CPUs means +a slower total emulation speed. + +

+ + +

Assuming you have done the root-on-nfs setup detailed above, uncomment +the bsd.mp file in the configuration file, and set ncpus to the +number of cpus (1 through 4). + +

If you want to start the emulator from the command line with multiple +processors, use the -n option. + diff -Nru gxemul-0.6.2/doc/machine_mvme88k.html gxemul-0.7.0+dfsg/doc/machine_mvme88k.html --- gxemul-0.6.2/doc/machine_mvme88k.html 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/machine_mvme88k.html 2021-11-27 09:42:23.000000000 +0000 @@ -16,7 +16,7 @@ -

This emulation mode attempts to emulate a Motorola MVME187 machine. -Note that these were based on Motorola 88000 processors, not 68000. - - +Note that these were based on +Motorola 88000 +processors, not 68000. @@ -71,7 +70,7 @@

  • Download the entire mvme88k directory from the ftp server:
    -	wget -np -l 0 -r ftp://ftp.se.openbsd.org/pub/OpenBSD/4.5/mvme88k/
    +	wget -np -l 0 -r https://ftp.nluug.nl/OpenBSD/4.5/mvme88k/
     
     
    @@ -79,17 +78,17 @@ (I recommend using mkisofs for that purpose. If you don't already have mkisofs installed on your system, you need to install it in order to do this.)
    -	mkisofs -o openbsd_mvme88k_4.5.iso -U ftp.se.openbsd.org/pub/OpenBSD/
    +	mkisofs -o openbsd_mvme88k_4.5.iso -U ftp.nluug.nl/OpenBSD/
     
     
  • Copy away the kernel, we'll need it later. But remove the rest of the downloaded tree.
    -	cp ftp.se.openbsd.org/pub/OpenBSD/4.5/mvme88k/bsd .
    -	rm -rf ftp.se.openbsd.org
    +	cp ftp.nluug.nl/OpenBSD/4.5/mvme88k/bsd .
    +	rm -rf ftp.nluug.nl
     
  • Start the emulator using this command line:
    -	gxemul -e mvme187old -d obsd_mvme88k.img -d b:openbsd_mvme88k_4.5.iso -j 4.5/mvme88k/bsd.rd
    +	gxemul -e mvme187 -d obsd_mvme88k.img -d b:openbsd_mvme88k_4.5.iso -j 4.5/mvme88k/bsd.rd
     
     
    and proceed like you would do if you were installing OpenBSD @@ -268,7 +267,7 @@ Once the install has finished, the following command should let you boot from the harddisk image:
    -	gxemul -e mvme187old -d obsd_mvme88k.img bsd
    +	gxemul -e mvme187 -d obsd_mvme88k.img bsd
     

    When asked about root disk, enter sd0. diff -Nru gxemul-0.6.2/doc/machines/machine_cyclonevh.html.SKEL gxemul-0.7.0+dfsg/doc/machines/machine_cyclonevh.html.SKEL --- gxemul-0.6.2/doc/machines/machine_cyclonevh.html.SKEL 2019-06-22 18:23:29.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/machines/machine_cyclonevh.html.SKEL 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ - -The cyclonevh machine template tries to emulate a -Cyclone/VH i960 evaluation board. - -

    Its only purpose is to allow experiments with uClinux/i960 binaries. - -See https://web.archive.org/web/20010417034914/http://www.cse.ogi.edu/~kma/uClinux.html for more info. - -

    NOTE! - -

    A binary (vmlinux) can be found on this page: -
    -https://web.archive.org/web/20010417034914/http://www.cse.ogi.edu/~kma/uClinux.html - -

    However, there is also a binary at -http://www.uclinux.org/pub/uClinux/ports/i960/, which is corrupt; -it seems to have been uploaded/encoded with the wrong character encoding. -(At least it is broken as of 2016-04-18.) - -

    TODO: -
    Everything. - -

    Until there is an ECOFF file loader, the vmlinux binary image may be -experimented with manually, using the raw file loader. - -

    -$ ./gxemul -V -e cyclonevh raw:0xa3c08000:0xb8:0xa3c08020:vmlinux 
    -
    -GXemul (unknown version)      Copyright (C) 2003-2018  Anders Gavare
    -
    -  mainbus0
    -  |-- cpu0  (25 MHz)
    -  \-- ram0  (4 MB at offset 0xa3c00000)
    -
    -cpu0: raw:0xa3c08000:0xb8:0xa3c08020:/home/debug/emul/i960/vmlinux loaded
    -      Raw file: entry point 0xa3c08020
    -      loadable chunk at offset 184: vaddr 0xa3c08000, 774924 bytes
    -
    -GXemul> cp.u 
    -0xa3c08020 <- 58a0198c            unimplemented: 88 
    -0xa3c08024    64a50294            unimplemented: 100
    -0xa3c08028    58a0198d            unimplemented: 88 
    -0xa3c0802c    65a50294            unimplemented: 101
    -0xa3c08030    09000700            unimplemented: 9  
    -0xa3c08034    8c803000            lda               
    -0xa3c08038    a3c08000            unimplemented: 163
    -0xa3c0803c    090077a4            unimplemented: 9  
    -0xa3c08040    08000000            unimplemented: 8  
    -0xa3c08044    00000000            unimplemented: 0  
    -0xa3c08048    00000000            unimplemented: 0  
    -0xa3c0804c    00000000            unimplemented: 0  
    -0xa3c08050    8cf03000            lda               
    -0xa3c08054    a3c08064            unimplemented: 163
    -0xa3c08058    5c80161e            unimplemented: 92 
    -0xa3c0805c    5cf01e00            unimplemented: 92 
    -0xa3c08060    84041000            unimplemented: 132
    -0xa3c08064    0a000000            unimplemented: 10 
    -0xa3c08068    74696e69            unimplemented: 116
    -0xa3c0806c    00000000            unimplemented: 0  
    -GXemul> quit
    -
    - -


    - - diff -Nru gxemul-0.6.2/doc/machines/machine_hp700rx.html.SKEL gxemul-0.7.0+dfsg/doc/machines/machine_hp700rx.html.SKEL --- gxemul-0.6.2/doc/machines/machine_hp700rx.html.SKEL 2019-06-22 18:23:29.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/machines/machine_hp700rx.html.SKEL 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ - -The hp700rx machine template tries to emulate a -HP 700/RX X-terminal, with an i960CA processor. - -

    TODO: -
    Everything. NOTHING ACTUALLY WORKS YET. -These are preliminary notes I am using during development. - -

    Alternative 1. Use the ROM from your real machine.

    - -
    $ gxemul -V -e hp700rx raw:0xfff80000:0:0xfff8b000:hp700rx-rom.bin
    -GXemul (unknown version)      Copyright (C) 2003-2019  Anders Gavare
    -
    -  mainbus0
    -  |-- cpu0  (i960CA, 25 MHz)
    -  |-- ram0  (2 MB at offset 0x3fe00000)
    -  \-- rom0  (512 KB at offset 0xfff80000)
    -
    -cpu0: raw:0xfff80000:0:0xfff8b000:hp700rx-rom.bin loaded
    -      Raw file: entry point 0xfff8b000
    -      loadable chunk: vaddr 0xfff80000, 524288 bytes
    -
    -GXemul> cp.u 
    -0xfff8b000 <- 5c801610            mov      g0,g0        
    -0xfff8b004    5c801610            mov      g0,g0        
    -0xfff8b008    8c180402            lda      0x402,r3     
    -0xfff8b00c    6518c483            sysctl   r3,r3,r3     
    -0xfff8b010    8c180403            lda      0x403,r3     
    -0xfff8b014    6518c483            sysctl   r3,r3,r3     
    -0xfff8b018    8c180404            lda      0x404,r3     
    -0xfff8b01c    6518c483            sysctl   r3,r3,r3     
    -0xfff8b020    8c180405            lda      0x405,r3     
    -0xfff8b024    6518c483            sysctl   r3,r3,r3     
    -0xfff8b028    8c183000 001f0002   lda      0x001f0002,r3
    -0xfff8b030    5c201e02            mov      2,r4         
    -0xfff8b034    6520ca80            modpc    0,r3,r4      
    -0xfff8b038    5c083e00            mov      0,sfr1       
    -0xfff8b03c    5c003e00            mov      0,sfr0       
    -0xfff8b040    8c203000 30000400   lda      0x30000400,r4
    -0xfff8b048    5c081604            mov      r4,sp        
    -0xfff8b04c    59185e0c            shlo     12,1,r3      
    -0xfff8b050    6420c283            modac    r3,r3,r4     
    -0xfff8b054    8c803000 c0003800   lda      0xc0003800,g0
    -GXemul> quit 
    -
    - - -

    Alternative 2. Use the C2708A X-server binary.

    - -
    $ ./gxemul -V -e hp700rx C2708A 
    -
    - -

    but the entry point (according to Intel's b.out format) is 0x3fe05000, -which is wrong. Clearly, the HP 700/RX deduces the entry point some other -way. For now, one way to load the binary with correct entry point is -to use the "raw" file loader and specify addresses explicitly: - -

    $ ./gxemul -V -e hp700rx raw:0x3fe05000:0x2c:0x3fe05094:C2708A 
    -GXemul (unknown version)      Copyright (C) 2003-2019  Anders Gavare
    -
    -  mainbus0
    -  |-- cpu0  (i960CA, 25 MHz)
    -  |-- ram0  (2 MB at offset 0x3fe00000)
    -  \-- rom0  (512 KB at offset 0xfff80000)
    -
    -cpu0: raw:0x3fe05000:0x2c:0x3fe05094:C2708A loaded
    -      Raw file: entry point 0x3fe05094
    -      loadable chunk at offset 44: vaddr 0x3fe05000, 1605668 bytes
    -
    -GXemul> cpu.u 
    -0x3fe05094 <- 8c180100            lda      0x100,r3      
    -0x3fe05098    6518c483            sysctl   r3,r3,r3      
    -0x3fe0509c    5c201e06            mov      6,r4          
    -0x3fe050a0    8c683000 c0003000   lda      0xc0003000,r13
    -0x3fe050a8    82235000            stob     r4,(r13)      
    -0x3fe050ac    5c881e08            mov      8,g1          
    -0x3fe050b0    90745000            ld       (g1),r14      
    -0x3fe050b4    5cf01e00            mov      0,g14         
    -0x3fe050b8    8c183000 001f0002   lda      0x001f0002,r3 
    -0x3fe050c0    8c203000 001f0002   lda      0x001f0002,r4 
    -0x3fe050c8    6520ca80            modpc    0,r3,r4       
    -0x3fe050cc    5c103e00            mov      0,sfr2        
    -0x3fe050d0    5c083e00            mov      0,sfr1        
    -0x3fe050d4    5c003e00            mov      0,sfr0        
    -0x3fe050d8    5c001e00            mov      0,pfp         
    -0x3fe050dc    8cf80040            lda      0x40,fp       
    -0x3fe050e0    8c0fe040            lda      0x40(fp),sp   
    -0x3fe050e4    59185e0c            shlo     12,1,r3       
    -0x3fe050e8    6420c283            modac    r3,r3,r4      
    -0x3fe050ec    59805e1e            shlo     30,1,g0       
    -GXemul> q 
    -
    - -


    - - diff -Nru gxemul-0.6.2/doc/machines/machine_mvme187.html.SKEL gxemul-0.7.0+dfsg/doc/machines/machine_mvme187.html.SKEL --- gxemul-0.6.2/doc/machines/machine_mvme187.html.SKEL 2019-06-22 18:23:29.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/machines/machine_mvme187.html.SKEL 1970-01-01 00:00:00.000000000 +0000 @@ -1,241 +0,0 @@ - -The mvme187 machine is a -VMEbus based machine with a -Motorola 88100 CPU. - - -


    - -

    OpenBSD/mvme88k:

    - -NOTE: THIS DOES NOT WORK YET! These are preliminary -instructions on how it may work when the new GXemul framework is -complete enough. - -

    It is possible to run -OpenBSD/mvme88k -on the emulated Motorola MVME187 machine. - -

    To install OpenBSD/mvme88k onto an emulated harddisk image, follow these -instructions: - -

    -

      -
    1. Create an empty harddisk image, which will be the root disk - that OpenBSD installs itself onto:
      -	dd if=/dev/zero of=obsd_mvme88k.img bs=1024 count=1 seek=1900000
      -
      -
      -
    2. Download the entire mvme88k directory from the ftp server:
      -	wget -np -l 0 -r ftp://ftp.se.openbsd.org/pub/OpenBSD/4.4/mvme88k/
      -
      -
      - -
    3. You now need to make an ISO image of the entire directory you downloaded. - (I recommend using mkisofs for that purpose. If you don't - already have mkisofs installed on your system, you need - to install it in order to do this.)
      -	mkisofs -o openbsd_mvme88k_4.4.iso -U ftp.se.openbsd.org/pub/OpenBSD/
      -
      -
      -
    4. Copy away the kernel, we'll need it later. But remove the rest of the - downloaded tree.
      -	cp ftp.se.openbsd.org/pub/OpenBSD/4.4/mvme88k/bsd .
      -	rm -rf ftp.se.openbsd.org
      -
      - -
    5. Start the emulator using this command line:
      -	gxemul -e mvme187 -d obsd_mvme88k.img -d b:openbsd_mvme88k_4.4.iso -j 4.4/mvme88k/bsd.rd
      -
      -
      - and proceed like you would do if you were installing OpenBSD - on a real MVME187. There is a problem with finding the filesystem on - the CDROM, since there is no disklabel [and/or because the emulator - perhaps does not simulate CDROM TOCs well enough], but it's possible - to mount - the filesystem using manual intervention. Here is an example of what - an install can look like: (user input in blue italic)
      -	CPU0 is associated to 2 MC88200 CMMUs
      -	Copyright (c) 1982, 1986, 1989, 1991, 1993
      -		The Regents of the University of California.  All rights reserved.
      -	Copyright (c) 1995-2008 OpenBSD. All rights reserved.  http://www.OpenBSD.org
      -
      -	OpenBSD 4.4 (RAMDISK) #19: Sun Aug 10 21:03:44 GMT 2008
      -	    root@arzon.gentiane.org:/usr/src/sys/arch/mvme88k/compile/RAMDISK
      -	real mem = 67108864 (64MB)
      -	avail mem = 56791040 (54MB)
      -	mainbus0 at root: Motorola MVME187, 33MHz
      -	cpu0: M88100 rev 0x3, 2 CMMU
      -	cpu0: M88200 (16K) rev 0x9, full Icache, M88200 (16K) rev 0x9, full Dcache
      -	pcctwo0 at mainbus0 addr 0xfff00000: rev 0
      -	nvram0 at pcctwo0 offset 0xc0000: MK48T08
      -	cl0 at pcctwo0 offset 0x45000 ipl 3: console
      -	osiop0 at pcctwo0 offset 0x47000 ipl 2: NCR53C710 rev 2, 66MHz
      -	scsibus0 at osiop0: 8 targets, initiator 7
      -	osiop0: target 0 ignored sync request
      -	osiop0: target 0 now using 8 bit asynch xfers
      -	sd0 at scsibus0 targ 0 lun 0:  SCSI2 0/direct fixed
      -	sd0: 1855MB, 1855 cyl, 16 head, 128 sec, 512 bytes/sec, 3800003 sec total
      -	osiop0: target 1 ignored sync request
      -	osiop0: target 1 now using 8 bit asynch xfers
      -	cd0 at scsibus0 targ 1 lun 0:  SCSI2 5/cdrom removable
      -	vme0 at pcctwo0 offset 0x40000
      -	vme0: using BUG parameters
      -	vme0: vme to cpu irq level 1:1
      -	vmes0 at vme0
      -	rd0: fixed, 4096 blocks
      -	boot device: 
      -	root on rd0a swap on rd0b dump on rd0b
      -	WARNING: clock gained 138 days -- CHECK AND RESET THE DATE!
      -	erase ^?, werase ^W, kill ^U, intr ^C, status ^T
      -	(I)nstall, (U)pgrade or (S)hell? i
      -
      -	Welcome to the OpenBSD/mvme88k 4.4 install program.
      -
      -	This program will help you install OpenBSD. At any prompt except password
      -	prompts you can escape to a shell by typing '!'. Default answers are shown
      -	in []'s and are selected by pressing RETURN.  At any time you can exit this
      -	program by pressing Control-C, but exiting during an install can leave your
      -	system in an inconsistent state.
      -
      -	Terminal type? [vt100] xterm
      -
      -	IS YOUR DATA BACKED UP? As with anything that modifies disk contents, this
      -	program can cause SIGNIFICANT data loss.
      -
      -	It is often helpful to have the installation notes handy. For complex disk
      -	configurations, relevant disk hardware manuals and a calculator are useful.
      -
      -	Proceed with install? [no] yes
      -	Cool! Let's get to it.
      -
      -	You will now initialize the disk(s) that OpenBSD will use. To enable all
      -	available security features you should configure the disk(s) to allow the
      -	creation of separate filesystems for /, /tmp, /var, /usr, and /home.
      -
      -	Available disks are: sd0.
      -	Which one is the root disk? (or 'done') [sd0] sd0
      -	osiop0: target 0 ignored sync request
      -	osiop0: target 0 now using 8 bit asynch xfers
      -	Initial label editor (enter '?' for help at any prompt)
      -	> a a
      -	offset: [0] 63
      -	size: [3799940] 3500000
      -	FS type: [4.2BSD] 
      -	mount point: [none] /
      -	> a b
      -	offset: [3500063] 
      -	size: [299940] 
      -	FS type: [swap] 
      -	> w
      -	> q
      -	No label changes.
      -	No more disks to initialize.
      -
      -	OpenBSD filesystems:
      -	sd0a /
      -
      -	The next step *DESTROYS* all existing data on these partitions!
      -	Are you really sure that you're ready to proceed? [no] yes
      -	/dev/rsd0a: 1709.0MB in 3500000 sectors of 512 bytes
      -	9 cylinder groups of 202.47MB, 12958 blocks, 25984 inodes each
      -	/dev/sd0a on /mnt type ffs (rw, asynchronous, local, ctime=Thu Jan  1 16:29:57 2009)
      -
      -	System hostname? (short form, e.g. 'foo') test
      -	Configure the network? [yes] no
      -	Password for root account? (will not echo) 
      -	Password for root account? (again) 
      -
      -	Let's install the sets!
      -	Location of sets? (cd disk ftp http nfs or 'done') [cd] disk
      -	Is the disk partition already mounted? [no] !mount -t cd9660 /dev/cd0c /mnt2
      -	osiop0: target 1 ignored sync request
      -	osiop0: target 1 now using 8 bit asynch xfers
      -	Is the disk partition already mounted? [no] yes
      -	Pathname to the sets? (or 'done') [4.4/mvme88k] /mnt2/4.4/mvme88k
      -
      -	Select sets by entering a set name, a file name pattern or 'all'. De-select
      -	sets by prepending a '-' to the set name, file name pattern or 'all'. Selected
      -	sets are labelled '[X]'.
      -
      -	        [X] bsd
      -	        [X] bsd.rd
      -	        [ ] bsd.mp
      -	        [X] base44.tgz
      -	        [X] etc44.tgz
      -	        [X] misc44.tgz
      -	        [X] comp44.tgz
      -	        [X] man44.tgz
      -	        [X] game44.tgz
      -	        [ ] xbase44.tgz
      -	        [ ] xetc44.tgz
      -	        [ ] xshare44.tgz
      -	        [ ] xfont44.tgz
      -	        [ ] xserv44.tgz
      -	Set name? (or 'done') [bsd.mp] done
      -	Ready to install sets? [yes] yes
      -	Getting bsd ...
      -	100% |**************************************************|  2329 KB    01:21    
      -	Getting bsd.rd ...
      -	100% |**************************************************|  3150 KB    01:48    
      -	Getting base44.tgz ...
      -	100% |**************************************************| 87686 KB    11:56    
      -	Getting etc44.tgz ...
      -	100% |**************************************************|   629 KB    00:14    
      -	Getting misc44.tgz ...
      -	100% |**************************************************|  2866 KB    00:37    
      -	Getting comp44.tgz ...
      -	100% |**************************************************| 38869 KB    06:19    
      -	Getting man44.tgz ...
      -	100% |**************************************************|  6967 KB    01:50    
      -	Getting game44.tgz ...
      -	100% |**************************************************|  7037 KB    01:16    
      -	Location of sets? (cd disk ftp http nfs or 'done') [done] done
      -	Start sshd(8) by default? [yes] yes
      -	Start ntpd(8) by default? [no] no
      -	Saving configuration files...done.
      -	Generating initial host.random file...done.
      -	What timezone are you in? ('?' for list) [Canada/Mountain] Europe/Stockholm
      -	Setting local timezone to 'Europe/Stockholm'...done.
      -	Making all device nodes...done.
      -	Installing boot block...
      -	boot: /mnt/boot
      -	proto: /mnt/usr/mdec/bootxx
      -	device: /dev/rsd0a
      -	cdevice: /dev/rsd0c
      -	modifying vid.
      -	/mnt/usr/mdec/bootxx: entry point 0x9f0000
      -	proto bootblock size 5120
      -	room for 64 filesystem blocks at 0x9f1198
      -	Will load 2 blocks of size 16384 each.
      -	0: 17696
      -	1: 17728
      -
      -	CONGRATULATIONS! Your OpenBSD install has been successfully completed!
      -	To boot the new system, enter halt at the command prompt. Once the
      -	system has halted, reset the machine and boot from the disk.
      -	# umount /mnt
      -	# halt
      -
      -
      -
    - -

    -Once the install has finished, the following command should let you -boot from the harddisk image: -

    -	gxemul -e mvme187 -d obsd_mvme88k.img bsd
    -
    - -

    When asked about root disk, enter sd0. - -

    No NIC has been implemented yet for mvme187, so there is no network connectivity -from within the guest OS. - - - - - -


    - - diff -Nru gxemul-0.6.2/doc/machines/machine_testm88k.html.SKEL gxemul-0.7.0+dfsg/doc/machines/machine_testm88k.html.SKEL --- gxemul-0.6.2/doc/machines/machine_testm88k.html.SKEL 2019-06-22 18:23:29.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/machines/machine_testm88k.html.SKEL 1970-01-01 00:00:00.000000000 +0000 @@ -1,161 +0,0 @@ -

    - -

    The testm88k machine is a GXemul-specific machine used for simple -tests. It is based around a -Motorola 88100 CPU, -and some simple devices. - -

    To start the emulator with a binary built for the testm88k machine, -type: -

    -	gxemul -e testm88k filename
    -
    - -

    You may add -V to start in the paused mode, and enter the single-step -debugger. - -

    Example: -

    -$ gxemul -V -e testm88k test/FileLoader_A.OUT_M88K
    -GXemul (unknown version)      Copyright (C) 2003-2010  Anders Gavare
    -
    -  mainbus0
    -  |-- cpu0  (88100, 50 MHz)
    -  |-- ram0  (32 MB at offset 0)
    -  |-- fb_videoram0  (15 MB at offset 0x12000000)
    -  \-- rom0  (4 MB at offset 0xff800000)
    -
    -cpu0: test/FileLoader_A.OUT_M88K loaded
    -      a.out: entry point 0x000012b8
    -      text + data = 4096 + 4096 bytes
    -      symbols: 1260 bytes at 0x2000
    -      strings: 1070 bytes at 0x24ec
    -      13 symbols read
    -
    -GXemul> cpu0.unassemble
    -<_f>      
    -0x12b8 <- 67ff0020   subu    r31,r31,0x20 
    -0x12bc    27df0010   st      r30,r31,0x10 
    -0x12c0    63df0010   addu    r30,r31,0x10 
    -0x12c4    58400320   or      r2,r0,0x320  
    -0x12c8    58600258   or      r3,r0,0x258  
    -0x12cc    243f0014   st      r1,r31,0x14  
    -0x12d0    231f0008   st.d    r24,r31,0x8  
    -0x12d4    cfffffe7   bsr.n   0x1270          ; <_change_resolution>
    -0x12d8    f6c0201f   st.d    r22,r0,r31   
    -0x12dc    cbffff89   bsr     0x1100          ; <_my_random>        
    -0x12e0    f6c05802   or      r22,r0,r2    
    -0x12e4    69b60320   divu    r13,r22,0x320
    -0x12e8    6dad0320   mulu    r13,r13,0x320
    -0x12ec    cfffff85   bsr.n   0x1100          ; <_my_random>        
    -0x12f0    f6d6640d   subu    r22,r22,r13  
    -0x12f4    f6e05802   or      r23,r0,r2    
    -0x12f8    69b70258   divu    r13,r23,0x258
    -0x12fc    6dad0258   mulu    r13,r13,0x258
    -0x1300    cfffff80   bsr.n   0x1100          ; <_my_random>        
    -0x1304    f6f7640d   subu    r23,r23,r13  
    -GXemul> cpu0.registers
    -   pc = 0x000012b8  <_f>
    -   r0 = 0x00000000     r1 = 0x00000000     r2 = 0x00000000     r3 = 0x00000000
    -   r4 = 0x00000000     r5 = 0x00000000     r6 = 0x00000000     r7 = 0x00000000
    -   r8 = 0x00000000     r9 = 0x00000000    r10 = 0x00000000    r11 = 0x00000000
    -  r12 = 0x00000000    r13 = 0x00000000    r14 = 0x00000000    r15 = 0x00000000
    -  r16 = 0x00000000    r17 = 0x00000000    r18 = 0x00000000    r19 = 0x00000000
    -  r20 = 0x00000000    r21 = 0x00000000    r22 = 0x00000000    r23 = 0x00000000
    -  r24 = 0x00000000    r25 = 0x00000000    r26 = 0x00000000    r27 = 0x00000000
    -  r28 = 0x00000000    r29 = 0x00000000    r30 = 0x00000000    r31 = 0x00000ff0
    -GXemul> step 6 
    -step 0: cpu0: <_f>      
    -              0x12b8    67ff0020   subu   r31,r31,0x20
    -        => cpu0.pc: 0x12b8 -> 0x12bc
    -        => cpu0.r31: 0xff0 -> 0xfd0
    -
    -step 1: cpu0: 0x12bc    27df0010   st   r30,r31,0x10
    -        => cpu0.pc: 0x12bc -> 0x12c0
    -
    -step 2: cpu0: 0x12c0    63df0010   addu   r30,r31,0x10
    -        => cpu0.pc: 0x12c0 -> 0x12c4
    -        => cpu0.r30: 0 -> 0xfe0
    -
    -step 3: cpu0: 0x12c4    58400320   or   r2,r0,0x320
    -        => cpu0.pc: 0x12c4 -> 0x12c8
    -        => cpu0.r2: 0 -> 0x320
    -
    -step 4: cpu0: 0x12c8    58600258   or   r3,r0,0x258
    -        => cpu0.pc: 0x12c8 -> 0x12cc
    -        => cpu0.r3: 0 -> 0x258
    -
    -step 5: cpu0: 0x12cc    243f0014   st   r1,r31,0x14
    -        => cpu0.pc: 0x12cc -> 0x12d0
    -GXemul> cpu0.showFunctionTraceCall = true
    -=> cpu0.showFunctionTraceCall: false -> true
    -GXemul> continue
    -[ cpu0: _change_resolution(800,600,0,0,0,0,0,0,...) ]
    -[ cpu0:   _fbctrl_set_x1(800,600,0,0,0,0,0,0,...) ]
    -[ cpu0:     _fbctrl_write_port(1,600,0,0,0,0,0,0,...) ]
    -[ cpu0:     _fbctrl_write_data(800,600,0,0,0,0,0,0x12f00000,...) ]
    -[ cpu0:   _fbctrl_set_y1(600,600,0,0,0,0,0,0x12f00010,...) ]
    -[ cpu0:     _fbctrl_write_port(2,600,0,0,0,0,0,0x12f00010,...) ]
    -[ cpu0:     _fbctrl_write_data(600,600,0,0,0,0,0,0x12f00000,...) ]
    -[ cpu0:   _fbctrl_command(1,600,0,0,0,0,0,0x12f00010,...) ]
    -[ cpu0:     _fbctrl_write_port(0,600,0,0,0,0,0,0x12f00010,...) ]
    -[ cpu0:     _fbctrl_write_data(1,600,0,0,0,0,0,0x12f00000,...) ]
    -[ cpu0: _my_random(1,600,0,0,0,0,0,0x12f00010,...) ]
    -[ cpu0: _my_random(0x8eb1badd,258,0,0,0,0,0x96219136,0xe3abd777,...) ]
    -[ cpu0: _my_random(0x6c3eea31,258,0,0,0,0,0x96219136,0x9a0bfc0b,...) ]
    -[ cpu0: _my_random(0x159ec14d,258,0,0,0,0,0x96219136,0xd96944e7,...) ]
    -[ cpu0: _my_random(0x56fc79a1,258,0,0,0,0,0x96219136,0x30a2827b,...) ]
    -[ cpu0: _draw_rectangle(381,513,109,185,0xbf37bf3d,0,0x96219136,0x1c9221d7,...) ]
    -[ cpu0: _my_random(381,513,109,185,0xbf37bf3d,0,0x96219136,0x1c9221d7,...) ]
    -[ cpu0: _my_random(0x93071c91,201,6d,b9,0xbf37bf3d,0,0x96219136,0x2d57546b,...) ]
    -[ cpu0: _my_random(0xa2c2692d,201,6d,b9,0xbf37bf3d,0,0x96219136,0x38c76ac7,...) ]
    -[ cpu0: _my_random(0xb7525781,201,6d,b9,0xbf37bf3d,0,0x96219136,0x96563e5b,...) ]
    -[ cpu0: _my_random(0x19c3031d,201,6d,b9,0xbf37bf3d,0,0x96219136,0x1fd1a3b7,...) ]
    -[ cpu0: _draw_rectangle(17,101,481,117,0x90449ef1,0,0x96219136,0xfe6cfccb,...) ]
    -[ cpu0:   _my_memset(0x1203b313,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0xfe6cfccb,...) ]
    -[ cpu0:   _my_memset(0x1203bc73,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x1203c5d3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x1203cf33,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x1203d893,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x1203e1f3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x1203eb53,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x1203f4b3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -^C
    -[ cpu0:   _my_memset(0x1203fe13,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x12040773,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x120410d3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x12041a33,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x12042393,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x12042cf3,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ cpu0:   _my_memset(0x12043653,0x90449ef1,0x573,75,0x90449ef1,0,0x96219136,0,...) ]
    -[ 100006 steps (1104 steps/second) ]
    -GXemul> fb_videoram0.dump 0x3b300
    -TODO: parse address expression
    -(for now, only hex immediate values are supported!)
    -0003b300  00000000 00000000 00000000 00000000  ................
    -0003b310  000000f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b320  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b330  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b340  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b350  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b360  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b370  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b380  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b390  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b3a0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b3b0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b3c0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b3d0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b3e0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -0003b3f0  f1f1f1f1 f1f1f1f1 f1f1f1f1 f1f1f1f1  ................
    -GXemul> quit
    -
    -
    - -

    -Source code for this component can be found -here. - -



    - - Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/machines/machine_testm88k.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/machines/machine_testm88k.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/machines/machine_testm88k-thumb.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/machines/machine_testm88k-thumb.png differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/doc/machines/machine_testmips-thumb.png and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/doc/machines/machine_testmips-thumb.png differ diff -Nru gxemul-0.6.2/doc/machine_sgi_o2.html gxemul-0.7.0+dfsg/doc/machine_sgi_o2.html --- gxemul-0.6.2/doc/machine_sgi_o2.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/machine_sgi_o2.html 2021-11-27 09:42:23.000000000 +0000 @@ -16,7 +16,7 @@ -

    Release notes for GXemul 0.6.2

    +

    Release notes for GXemul 0.7.0

    -

    Copyright (C) 2003-2019 Anders Gavare +

    Copyright (C) 2003-2021 Anders Gavare


    GXemul is a framework for full-system computer architecture emulation. Several processor architectures and machine types have been implemented. -It is working well enough to allow unmodified -"guest" operating systems to run inside the emulator, -as if they were running on real hardware. +It is working well enough to allow unmodified "guest" operating systems to run +inside the emulator, as if they were running on real hardware.

    The emulator emulates (networks of) real machines. The machines may consist of ARM, MIPS, Motorola 88K, PowerPC, and SuperH processors, and various @@ -25,65 +24,165 @@ controllers, ethernet controllers, disk controllers, and serial port controllers. -

    The documentation lists the machines and -guest operating systems that can be regarded as "working" in GXemul. -The first guest operating system that worked in GXemul was -NetBSD/pmax on -an emulated DECstation 5000/200, and that is -still one of the guest OSes that works best. +


    The changes between release 0.6.3.1 and 0.7.0 include: +

      +
    • The LUNA-88K machine now has + working SCSI emulation. This allows + OpenBSD/luna88k to be installed and run using a harddisk image. + (Previously, a more complicated root-on-nfs setup had to be used.) + +

      +

    • There is now a shorthand disk image prefix 'R' (uppercase), to reduce + the amount of typing when one wants to use a temporary throwaway + disk image overlay, that is when one does not want to allow + writes to a disk image. Previously, this would require + something like: +
      • +touch overlay.img overlay.img.map
        +gxemul -e ..... -d disk.img -d V0:overlay.img
        +rm overlay.img overlay.img.map
        +
      +

      which now becomes just: +

      • gxemul -e ..... -d R:disk.img
        +
      +

      The difference to using an explicit V: overlay is that the + temporary file is + removed automatically when the GXemul process exits. A guest + operating system will still perceive the disk as writable. + +

      +

    • Networking using a tap device can now be enabled directly on the + command line using a new -L option. Previously, + tap devices could only be enabled when using configuration files. + +

      +

    • A bug has been fixed for MIPS R2000/R3000 when writing to + coprocessor 0's ENTRY LO register. This fixes a regression + introduced between 0.6.1 and 0.6.2 + where running xinit inside Sprite (on an emulated + DECstation) suddenly failed. + +

      +

    • A "mouse grab" mechanism has been implemented for X11 framebuffer + windows. Previously, + mouse movements occuring inside a framebuffer window were always + forwarded to the guest OS. Interaction was akward, in particular + due to mouse acceleration being performed by the guest OS. + Now, instead, the framebuffer window needs to + be clicked in, in order to activate mouse pointer grabbing. + When the grab mode is active, mouse movements (and button clicks) + are forwarded to the guest OS, and the host's mouse cursor is + hidden. Grab mode is released when typing Left CTRL + ALT, or + when otherwise changing focus to another X11 window. + +

      +

    • Previously, the behavior when using configuration files was to + always start new terminal windows (xterms) for emulated serial + I/O ports, similar to the -x command line option. This + has now been changed, so that new terminal windows are only used + if there are two or more machines in the same configuration + file. If you still want separate terminal windows to be launched + when using a configuration file with a single machine in it, you + now need to add -x to the command line. + +

      +

    • Some cleanup to make the -K command line option work + more like it was always supposed to. + This option should cause the emulator to show the + GXemul> debugger prompt whenever + the emulated program or guest operating system ends, + regardless of whether it was a normal shutdown or some form + of error. This is useful for example if you wish to disassemble + the code, or inspect register or memory content, at the point + of failure. Starting the emulator with -V also + implicitly sets -K. If neither -V nor -K + is used, and the guest OS halts with powerdown or "reboots", the emulator + should exit gracefully (for the machine modes where shutdown + functionality has been implemented via device support or + prom emulation support). + +

      (There are still many explicit exit() calls throughout the + code, which over time will need to be manually converted to work + with -K, but the most common ones are fixed.) + +

      +

    • -T has been fixed to work the way it was always intended to + work, namely to abort immediately on the first load or store + to non-existant memory. This is useful in combination with + -K, for example when implementing new machine modes + in the emulator or trying out unsupported guest operating + systems that access memory or devices in a not-yet-implemented + way. +

      +

    • Debug messages have traditionally been printed using the rather + course-grained debug() and fatal() + functions. Work has now begun to separate this into a number of + subsystems, which can have their verbosity levels be + individually controlled using the new verbosity + debugger command. This also standardizes the way debug messages + are formatted: + +
      • [ machine-and-cpu-path: subsystem-name component-or-function-name: text ]
      + +

      Most of the time, not all of these are shown. + machine-and-cpu-path, for example, is only shown if the message comes + from a context where a CPU is known to cause the message, + and there are multiple machines or CPUs being emulated. + The [ ] brackets are only shown when intermixing debug messages + with serial I/O coming from the emulated program or guest + operating system. +

      (There are still a huge amount of debug() + and fatal() calls in the code, especially in the + less commonly used code paths.) -


      The most important changes between release 0.6.1 and 0.6.2 are: +

      +

    • Output from the emulator is now subtly colorized, to make it + easier to quickly interpret the text. This is enabled by + launching the emulator with the environment variable + CLICOLOR set, or by usign the -G command line option. + The choice of colors was done to + a) be reasonably subtle, and b) work + with both light and dark terminal backgrounds. + Coloring can be explicitly disabled using -A (overriding + the presence of CLICOLOR), and + it is also disabled when outputting to a non-tty. +
    +

    The source code has been switched back from C++ to plain C:

      -
    • When writing to mirrored RAM ranges, any dyntrans translations - made in either the mirror or the mirrored ranges are - now invalidated. This means that an emulated SGI O2 can - now be used with up to 1 GB of RAM when - running OpenBSD/sgi as a guest OS. Previously, 256 MB - was the maximum amount of emulated RAM possible for - the SGI O2. - -

      -

    • A fix 2018-06-13 (between 0.6.0.1 and 0.6.0.2) for translation - invalidation when using larger - than 4 KB pages, which made HelenOS/malta run further, - caused a regression which broke NetBSD/hpcmips (on VR4121 - CPUs, which have 1 KB native page size). A bit of cleanup seems - to have fixed this, so that both NetBSD/hpcmips and - HelenOS/malta work now. - -

      -

    • Cleanup: The MIPS processor emulation implemented in the - "new framework", and the corresponding MIPS machine - modes in the new framework, have been removed. (All - meaningful MIPS emulation is in the old framework anyway.) +
    • The "new" framework was removed. Instead of two different emulators + in the same program, there's just the traditional emulation + framework.

      -

    • Documentation updates: +
    • A C compiler supporting the C99 standard is needed in + order to build GXemul. + +

      +

    • For third parties that package GXemul (e.g. for package managing + systems used by operating systems or distributions), + build scripts may need to be modified:
        -
      • Each emulated machine now has a page - of its own with the guest OSes or other software - that may run in that mode, rather than just having a - long unsorted list of guest OS installation instructions. -
      • Less focus on the "new framework", more focus on the - old framework where things actually work. -
      • An introduction to using - GXemul as a debugger. -
      • A general overhaul to remove old stuff, fix errors, - and make things easier to read. +
      • The unit tests (make test) are gone. +
      • The (optional) dependency on Valgrind is gone. It was used for + running leak detection during unit test execution, but + the unit tests were for the C++ framework. +
      • The (optional) dependency on Doxygen is gone. It was used for + building documentation of the source code in the + C++ framework. +
      • Automatic generation of machine and component documentation + is gone (make documentation). +
      • In summary: the doc/ directory is now just a + single level without sub-directories, containing static + content; nothing is generated at build time.
    -


    Please read the HISTORY file for more details. -

    To build the emulator, run the configure script, and then run -make. This should hopefully work on most Unix-like systems, with few -or no modifications to the source code. -

    Regarding files in the src/include/thirdparty/ directory: most of these are from other open source projects such as NetBSD. See individual source files for details, if you plan to redistribute GXemul in binary form, @@ -93,7 +192,5 @@ http://gavare.se/gxemul/. - - diff -Nru gxemul-0.6.2/doc/tail.html gxemul-0.7.0+dfsg/doc/tail.html --- gxemul-0.6.2/doc/tail.html 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/tail.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ - - -



    - - diff -Nru gxemul-0.6.2/doc/technical.html gxemul-0.7.0+dfsg/doc/technical.html --- gxemul-0.6.2/doc/technical.html 2019-06-22 18:23:28.000000000 +0000 +++ gxemul-0.7.0+dfsg/doc/technical.html 2021-11-27 09:42:23.000000000 +0000 @@ -16,7 +16,7 @@ MEMORY LEAK CATCH POINT, counter = " << counter << "\n"; - - if (counter == -42) - { - abort(); - } - } - - size_t hash_index = _DEBUG_NEW_HASH(pointer); -#if _DEBUG_NEW_FILENAME_LEN == 0 - ptr->file = file; -#else - if (line) - strncpy(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1) - [_DEBUG_NEW_FILENAME_LEN - 1] = '\0'; - else - ptr->addr = (void*)file; -#endif - ptr->line = line; - ptr->size = size; - { - fast_mutex_autolock lock(new_ptr_lock[hash_index]); - ptr->next = new_ptr_list[hash_index]; - new_ptr_list[hash_index] = ptr; - } - if (new_verbose_flag) - { - fast_mutex_autolock lock(new_output_lock); - fprintf(new_output_fp, - "new: allocated %p (size %u, ", - pointer, (unsigned) size); - if (line != 0) - print_position(ptr->file, ptr->line); - else - print_position(ptr->addr, ptr->line); - fprintf(new_output_fp, ")\n"); - } - total_mem_alloc += size; - return pointer; -} - -void* operator new[](size_t size, const char* file, int line) -{ - void* pointer = operator new(size, file, line); - new_ptr_list_t* ptr = - (new_ptr_list_t*)((char*)pointer - aligned_list_item_size); - assert((ptr->line & INT_MIN) == 0); - ptr->line |= INT_MIN; // Result from new[] if highest bit set: Set - return pointer; -} - -void* operator new(size_t size) throw(std::bad_alloc) -{ - return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); -} - -void* operator new[](size_t size) throw(std::bad_alloc) -{ - return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); -} - -#if !defined(__BORLANDC__) || __BORLANDC__ > 0x551 -void* operator new(size_t size, const std::nothrow_t&) throw() -{ - return operator new(size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); -} - -void* operator new[](size_t size, const std::nothrow_t&) throw() -{ - return operator new[](size, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); -} -#endif - -void operator delete(void* pointer) throw() -{ - if (pointer == NULL) - return; - size_t hash_index = _DEBUG_NEW_HASH(pointer); - fast_mutex_autolock lock(new_ptr_lock[hash_index]); - new_ptr_list_t** raw_ptr = search_pointer(pointer, hash_index); - if (raw_ptr == NULL) - { - fast_mutex_autolock lock2(new_output_lock); - fprintf(new_output_fp, "delete: invalid pointer %p at ", pointer); - print_position(_DEBUG_NEW_CALLER_ADDRESS, 0); - fprintf(new_output_fp, "\n"); - fflush(new_output_fp); - _DEBUG_NEW_ERROR_ACTION; - } - free_pointer(raw_ptr, _DEBUG_NEW_CALLER_ADDRESS, false); -} - -void operator delete[](void* pointer) throw() -{ - if (pointer == NULL) - return; - size_t hash_index = _DEBUG_NEW_HASH(pointer); - fast_mutex_autolock lock(new_ptr_lock[hash_index]); - new_ptr_list_t** raw_ptr = search_pointer(pointer, hash_index); - if (raw_ptr == NULL) - { - fast_mutex_autolock lock2(new_output_lock); - fprintf(new_output_fp, "delete[]: invalid pointer %p at ", pointer); - print_position(_DEBUG_NEW_CALLER_ADDRESS, 0); - fprintf(new_output_fp, "\n"); - fflush(new_output_fp); - _DEBUG_NEW_ERROR_ACTION; - } - free_pointer(raw_ptr, _DEBUG_NEW_CALLER_ADDRESS, true); -} - -#if HAS_PLACEMENT_DELETE -void operator delete(void* pointer, const char* file, int line) throw() -{ - if (new_verbose_flag) - { - fast_mutex_autolock lock(new_output_lock); - fprintf(new_output_fp, - "info: exception thrown on initializing object at %p (", - pointer); - print_position(file, line); - fprintf(new_output_fp, ")\n"); - } - operator delete(pointer); -} - -void operator delete[](void* pointer, const char* file, int line) throw() -{ - if (new_verbose_flag) - { - fast_mutex_autolock lock(new_output_lock); - fprintf(new_output_fp, - "info: exception thrown on initializing objects at %p (", - pointer); - print_position(file, line); - fprintf(new_output_fp, ")\n"); - } - operator delete[](pointer); -} - -void operator delete(void* pointer, const std::nothrow_t&) throw() -{ - operator delete(pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); -} - -void operator delete[](void* pointer, const std::nothrow_t&) throw() -{ - operator delete[](pointer, (char*)_DEBUG_NEW_CALLER_ADDRESS, 0); -} -#endif // HAS_PLACEMENT_DELETE - -int __debug_new_counter::_count = 0; - -/** - * Constructor to increment the count. - */ -__debug_new_counter::__debug_new_counter() -{ - ++_count; -} - -/** - * Destructor to decrement the count. When the count is zero, - * #check_leaks will be called. - */ -__debug_new_counter::~__debug_new_counter() -{ - if (--_count == 0 && new_autocheck_flag) - if (check_leaks()) - { - new_verbose_flag = true; -#if defined(__GNUC__) && __GNUC__ >= 3 - if (!getenv("GLIBCPP_FORCE_NEW") && !getenv("GLIBCXX_FORCE_NEW")) - fprintf(new_output_fp, -"*** WARNING: GCC 3 or later is detected, please make sure the\n" -" environment variable GLIBCPP_FORCE_NEW (GCC 3.2 and 3.3) or\n" -" GLIBCXX_FORCE_NEW (GCC 3.4 and later) is defined. Check the\n" -" README file for details.\n"); -#endif - } -} - -#endif // NDEBUG diff -Nru gxemul-0.6.2/src/main/EscapedString.cc gxemul-0.7.0+dfsg/src/main/EscapedString.cc --- gxemul-0.6.2/src/main/EscapedString.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/EscapedString.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2007-2010 Anders Gavare. 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. The name of the author 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 "EscapedString.h" - - -EscapedString::EscapedString(const string& str) - : m_str(str) -{ -} - - -string EscapedString::Generate() const -{ - string result = "\""; - - for (size_t i=0; i -#include -#include - -using std::ifstream; - -#include "AddressDataBus.h" -#include "Component.h" -#include "FileLoader.h" -#include "FileLoader_aout.h" -#include "FileLoader_bout.h" -#include "FileLoader_ELF.h" -#include "FileLoader_raw.h" - - -FileLoader::FileLoader(const string& filename) - : m_filename(filename) -{ - m_fileLoaders.push_back(new FileLoader_aout(filename)); - m_fileLoaders.push_back(new FileLoader_bout(filename)); - m_fileLoaders.push_back(new FileLoader_ELF(filename)); - m_fileLoaders.push_back(new FileLoader_raw(filename)); -} - - -const string& FileLoader::GetFilename() const -{ - return m_filename; -} - - -string FileLoader::DetectFileFormat(refcount_ptr& loader) const -{ - loader = NULL; - - // TODO: Disk images? - - ifstream file(m_filename.c_str()); - - unsigned char buf[512]; - memset(buf, 0, sizeof(buf)); - size_t amountRead = 0; - if (file.is_open()) { - file.read((char *)buf, sizeof(buf)); - amountRead = file.gcount(); - } - - // Ask all file loaders about how well they handle the format. Return - // the format string from the loader that had the highest score. - float bestMatch = 0.0; - string bestFormat = "Unknown"; - FileLoaderImplVector::const_iterator it = m_fileLoaders.begin(); - for (; it != m_fileLoaders.end(); ++it) { - float match; - string format = (*it)->DetectFileType(buf, amountRead, match); - if (match > bestMatch) { - bestMatch = match; - bestFormat = format; - loader = *it; - } - } - - if (bestMatch == 0.0 && !file.is_open()) - return "Not accessible"; - - return bestFormat; -} - - -bool FileLoader::Load(refcount_ptr component, ostream& messages) const -{ - AddressDataBus * bus = component->AsAddressDataBus(); - if (bus == NULL) { - // We cannot load into something that isn't an AddressDataBus. - messages << "Error: " << component->GenerateShortestPossiblePath() - << " is not an AddressDataBus.\n"; - return false; - } - - refcount_ptr loaderImpl; - string fileFormat = DetectFileFormat(loaderImpl); - - if (!loaderImpl.IsNULL()) - return loaderImpl->LoadIntoComponent(component, messages); - - messages << "Error: File format '" << - fileFormat << "' not yet implemented. TODO\n"; - - return false; -} - - -/*****************************************************************************/ - - -#ifdef WITHUNITTESTS - -#include "ComponentFactory.h" - -static void Test_FileLoader_Constructor() -{ - FileLoader fileLoader("test/FileLoader_ELF_MIPS"); - UnitTest::Assert("filename mismatch?", - fileLoader.GetFilename(), "test/FileLoader_ELF_MIPS"); -} - -static void Test_FileLoader_Constructor_NonExistingFile() -{ - FileLoader fileLoader("test/Nonexisting"); - UnitTest::Assert("filename mismatch?", - fileLoader.GetFilename(), "test/Nonexisting"); -} - -static void Test_FileLoader_DetectFileFormat_NonexistingFile() -{ - FileLoader fileLoader("test/Nonexisting"); - refcount_ptr loaderImpl; - UnitTest::Assert("file format detection failure?", - fileLoader.DetectFileFormat(loaderImpl), "Not accessible"); -} - -static void Test_FileLoader_DetectFileFormat_NonsenseFile() -{ - FileLoader fileLoader("test/FileLoader_NonsenseFile"); - refcount_ptr loaderImpl; - UnitTest::Assert("file format detection failure?", - fileLoader.DetectFileFormat(loaderImpl), "Unknown"); -} - -static void Test_FileLoader_DetectFileFormat_ELF32() -{ - FileLoader fileLoader("test/FileLoader_ELF_MIPS"); - refcount_ptr loaderImpl; - UnitTest::Assert("file format detection failure?", - fileLoader.DetectFileFormat(loaderImpl), "ELF32"); -} - -static void Test_FileLoader_DetectFileFormat_ELF64() -{ - FileLoader fileLoader("test/FileLoader_ELF_SH5"); - refcount_ptr loaderImpl; - UnitTest::Assert("file format detection failure?", - fileLoader.DetectFileFormat(loaderImpl), "ELF64"); -} - -static void Test_FileLoader_DetectFileFormat_aout_88K() -{ - FileLoader fileLoader("test/FileLoader_A.OUT_M88K"); - refcount_ptr loaderImpl; - UnitTest::Assert("file format detection failure?", - fileLoader.DetectFileFormat(loaderImpl), "a.out_M88K_fromBeginning"); -} - -static void Test_FileLoader_DetectFileFormat_bout_i960() -{ - FileLoader fileLoader("test/FileLoader_B.OUT_i960"); - refcount_ptr loaderImpl; - UnitTest::Assert("file format detection failure?", - fileLoader.DetectFileFormat(loaderImpl), "b.out_i960_little"); -} - -static refcount_ptr SetupTestMachineAndLoad( - string machineName, string fileName, bool ramAtZero) -{ - FileLoader fileLoader(fileName); - refcount_ptr machine = - ComponentFactory::CreateComponent(machineName); - UnitTest::Assert("could not add machine type?", !machine.IsNULL()); - - machine->SetVariableValue("name", "\"machine\""); - refcount_ptr component = - machine->LookupPath("machine.mainbus0.cpu0"); - UnitTest::Assert("could not look up CPU to load into?", - !component.IsNULL()); - - refcount_ptr ram = machine->LookupPath("machine.mainbus0.ram0"); - UnitTest::Assert("could not look up RAM?", !ram.IsNULL()); - if (ramAtZero) - ram->SetVariableValue("memoryMappedBase", "0"); - - stringstream messages; - UnitTest::Assert("could not load the file " + fileName + " for" - " machine " + machineName, fileLoader.Load(component, messages)); - - return machine; -} - -#if 0 -static void Test_FileLoader_Load_ELF32() -{ - // Yes, it is odd to load a MIPS binary into a RISC-V machine, but still... - refcount_ptr machine = - SetupTestMachineAndLoad("riscv-virt", "test/FileLoader_ELF_MIPS", false); - - // Read from CPU, to make sure the file was loaded: - refcount_ptr cpu = - machine->LookupPath("machine.mainbus0.cpu0"); - AddressDataBus * bus = cpu->AsAddressDataBus(); - bus->AddressSelect((int32_t)0x00010000); - uint32_t word = 0x12345678; - bus->ReadData(word, BigEndian); - UnitTest::Assert("memory (CPU) wasn't filled with data from the file?", - word, 0x8f8b8008); - - // Read directly from RAM too, to make sure the file was loaded: - refcount_ptr ram = - machine->LookupPath("machine.mainbus0.ram0"); - AddressDataBus * ramBus = ram->AsAddressDataBus(); - ramBus->AddressSelect(0x1000c); - uint32_t word2 = 0x12345678; - ramBus->ReadData(word2, BigEndian); - UnitTest::Assert("memory (RAM) wasn't filled with data from the file?", - word2, 0x006b7021); -} -#endif - -static void Test_FileLoader_Load_ELF64() -{ - refcount_ptr machine = - SetupTestMachineAndLoad("riscv-virt", "test/FileLoader_ELF_RISCV64", true); - - // Read from CPU, to make sure the file was loaded: - refcount_ptr cpu = - machine->LookupPath("machine.mainbus0.cpu0"); - AddressDataBus * bus = cpu->AsAddressDataBus(); - bus->AddressSelect((int32_t)0x00010078); - uint32_t word = 0x12345678; - bus->ReadData(word, BigEndian); - UnitTest::Assert("memory (CPU) wasn't filled with data from the file?", - word, 0x011122ec); - - // Read directly from RAM too, to make sure the file was loaded: - refcount_ptr ram = - machine->LookupPath("machine.mainbus0.ram0"); - AddressDataBus * ramBus = ram->AsAddressDataBus(); - ramBus->AddressSelect(0x1007c); - uint32_t word2 = 0x12345678; - ramBus->ReadData(word2, BigEndian); - UnitTest::Assert("memory (RAM) wasn't filled with data from the file?", - word2, 0x0010aa87); -} - -static void Test_FileLoader_Load_aout() -{ - refcount_ptr machine = - SetupTestMachineAndLoad("testm88k", "test/FileLoader_A.OUT_M88K", true); - - // Read from CPU, to make sure the file was loaded: - refcount_ptr cpu = - machine->LookupPath("machine.mainbus0.cpu0"); - AddressDataBus * bus = cpu->AsAddressDataBus(); - bus->AddressSelect((int32_t)0x12b8); - uint32_t word = 0x12345678; - bus->ReadData(word, BigEndian); - UnitTest::Assert("memory (CPU) wasn't filled with data from the file?", - word, 0x67ff0020); - - // Read directly from RAM too, to make sure the file was loaded: - refcount_ptr ram = - machine->LookupPath("machine.mainbus0.ram0"); - AddressDataBus * ramBus = ram->AsAddressDataBus(); - ramBus->AddressSelect(0x12e0); - uint32_t word2 = 0xfdecba98; - ramBus->ReadData(word2, BigEndian); - UnitTest::Assert("memory (RAM) wasn't filled with data from the file?", - word2, 0xf6c05802); -} - -UNITTESTS(FileLoader) -{ - UNITTEST(Test_FileLoader_Constructor); - UNITTEST(Test_FileLoader_Constructor_NonExistingFile); - - UNITTEST(Test_FileLoader_DetectFileFormat_NonexistingFile); - UNITTEST(Test_FileLoader_DetectFileFormat_NonsenseFile); - UNITTEST(Test_FileLoader_DetectFileFormat_ELF32); - UNITTEST(Test_FileLoader_DetectFileFormat_ELF64); - UNITTEST(Test_FileLoader_DetectFileFormat_aout_88K); - UNITTEST(Test_FileLoader_DetectFileFormat_bout_i960); - - // UNITTEST(Test_FileLoader_Load_ELF32); - UNITTEST(Test_FileLoader_Load_ELF64); - UNITTEST(Test_FileLoader_Load_aout); -} - -#endif diff -Nru gxemul-0.6.2/src/main/fileloaders/FileLoader_aout.cc gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_aout.cc --- gxemul-0.6.2/src/main/fileloaders/FileLoader_aout.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_aout.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,357 +0,0 @@ -/* - * Copyright (C) 2009-2010 Anders Gavare. 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -using std::setw; -using std::setfill; -using std::ifstream; - -#include "AddressDataBus.h" -#include "components/CPUComponent.h" -#include "FileLoader_aout.h" - -#include "thirdparty/exec_aout.h" - -struct aout_symbol { - uint32_t strindex; - uint32_t type; - uint32_t addr; -}; - - -FileLoader_aout::FileLoader_aout(const string& filename) - : FileLoaderImpl(filename) -{ -} - - -string FileLoader_aout::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const -{ - matchness = 0.9; - - if (buf[0]==0x00 && buf[1]==0x8b && buf[2]==0x01 && buf[3]==0x07) { - /* MIPS a.out */ - return "a.out_MIPS"; - } - if (buf[0]==0x00 && buf[1]==0x87 && buf[2]==0x01 && buf[3]==0x08) { - /* M68K a.out */ - // AOUT_FLAG_VADDR_ZERO_HACK for OpenBSD/mac68k - return "a.out_M68K_vaddr0"; - } -// Luna88k a.out for OpenBSD is _almost_ like for MVME88K... just a difference -// of entry point (?) -// if (buf[0]==0x00 && buf[1]==0x99 && buf[2]==0x01 && buf[3]==0x07) { -// /* OpenBSD/luna88k a.out */ -// return "a.out_M88K_fromBeginningEntryAfterHeader"; -// } - if (buf[0]==0x00 && buf[1]==0x99 && buf[2]==0x01 && buf[3]==0x0b) { - /* OpenBSD/M88K a.out */ - return "a.out_M88K_fromBeginning"; - } - if (buf[0]==0x00 && buf[1]==0x8f && buf[2]==0x01 && buf[3]==0x0b) { - /* ARM a.out */ - return "a.out_ARM_fromBeginning"; - } - if (buf[0]==0x00 && buf[1]==0x86 && buf[2]==0x01 && buf[3]==0x0b) { - /* i386 a.out (old OpenBSD and NetBSD etc) */ - return "a.out_i386_fromBeginning"; - } - if (buf[0]==0x01 && buf[1]==0x03 && buf[2]==0x01 && buf[3]==0x07) { - /* SPARC a.out (old 32-bit NetBSD etc) */ - return "a.out_SPARC_noSizes"; - } - if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { - /* DEC OSF1 on MIPS: */ - return "a.out_MIPS_osf1"; - } - - matchness = 0.0; - return ""; -} - - -static uint32_t unencode32(uint8_t *p, Endianness endianness) -{ - uint32_t res; - - if (endianness == BigEndian) - res = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24); - else - res = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); - - return res; -} - - -bool FileLoader_aout::LoadIntoComponent(refcount_ptr component, ostream& messages) const -{ - AddressDataBus* bus = component->AsAddressDataBus(); - if (bus == NULL) { - messages << "Target is not an AddressDataBus.\n"; - return false; - } - - ifstream file(Filename().c_str()); - if (!file.is_open()) { - messages << "Unable to read file.\n"; - return false; - } - - unsigned char buf[65536]; - - memset(buf, 0, sizeof(buf)); - file.seekg(0, std::ios_base::end); - uint64_t totalSize = file.tellg(); - file.seekg(0, std::ios_base::beg); - file.read((char *)buf, totalSize < sizeof(buf)? totalSize : sizeof(buf)); - size_t amountRead = file.gcount(); - - float matchness; - string format = DetectFileType(buf, amountRead, matchness); - - if (format == "") { - messages << "Unknown a.out format.\n"; - return false; - } - - file.seekg(0, std::ios_base::beg); - - Endianness endianness = BigEndian; - StateVariable* var = component->GetVariable("bigendian"); - if (var == NULL) { - messages << "Target does not have the 'bigendian' variable," - " which is needed to\n" - "load a.out files.\n"; - return false; - } - - endianness = var->ToInteger() == 0? LittleEndian : BigEndian; - - struct exec aout_header; - uint32_t entry, datasize, textsize; - int32_t symbsize = 0; - uint32_t vaddr, total_len; - - if (format.substr(format.length()-5, 5) == "_osf1") { - file.read((char *)buf, 32); - if (file.gcount() != 32) { - messages << "The file is too small to be an OSF1 a.out.\n"; - return false; - } - - vaddr = unencode32(buf + 16, endianness); - entry = unencode32(buf + 20, endianness); - - symbsize = 0; - file.seekg(0, std::ios_base::end); - /* This is of course wrong, but should work anyway: */ - textsize = (uint32_t) file.tellg() - 512; - datasize = 0; - file.seekg(512, std::ios_base::beg); - } else if (format.substr(format.length()-8, 8) == "_noSizes") { - file.seekg(0, std::ios_base::end); - textsize = (uint32_t) file.tellg() - 32; - datasize = 0; - vaddr = entry = 0; - file.seekg(32, std::ios_base::beg); - } else { - file.read((char *)&aout_header, sizeof(aout_header)); - if (file.gcount() != sizeof(aout_header)) { - messages << "The file is too small to be an a.out.\n"; - return false; - } - - entry = unencode32((unsigned char*)&aout_header.a_entry, endianness); - - vaddr = entry; - - if (format.substr(format.length()-7, 7) == "_vaddr0") - vaddr = 0; - - textsize = unencode32((unsigned char*)&aout_header.a_text, endianness); - datasize = unencode32((unsigned char*)&aout_header.a_data, endianness); - symbsize = unencode32((unsigned char*)&aout_header.a_syms, endianness); - } - - if (format.substr(format.length()-14, 14) == "_fromBeginning") { - file.seekg(0, std::ios_base::beg); - vaddr &= ~0xfff; - } - - messages.flags(std::ios::hex); - messages << "a.out: entry point 0x"; - messages << setw(8) << setfill('0') << (uint32_t) entry << "\n"; - - messages.flags(std::ios::dec); - messages << "text + data = " << textsize << " + " << datasize << " bytes\n"; - - // Load text and data: - total_len = textsize + datasize; - while (total_len != 0) { - int len = total_len > sizeof(buf) ? sizeof(buf) : total_len; - file.read((char *)buf, len); - len = file.gcount(); - if (len < 1) - break; - - // Write to the bus, one byte at a time. - for (int k=0; kAddressSelect(vaddr); - if (!bus->WriteData(buf[k])) { - messages.flags(std::ios::hex); - messages << "Failed to write data to virtual " - "address 0x" << vaddr << "\n"; - return false; - } - - ++ vaddr; - } - - total_len -= len; - } - - if (total_len != 0) { - messages << "Failed to read the entire file.\n"; - return false; - } - - SymbolRegistry* symbolRegistry = NULL; - CPUComponent* cpu = component->AsCPUComponent(); - if (cpu != NULL) - symbolRegistry = &cpu->GetSymbolRegistry(); - - // Symbols: - if (symbolRegistry != NULL && symbsize > 0) { - messages.flags(std::ios::dec); - messages << "symbols: " << symbsize << " bytes at 0x"; - messages.flags(std::ios::hex); - messages << file.tellg() << "\n"; - - vector symbolData; - symbolData.resize(symbsize); - file.read(&symbolData[0], symbsize); - if (file.gcount() != symbsize) { - messages << "Failed to read all symbols.\n"; - return false; - } - - off_t oldpos = file.tellg(); - file.seekg(0, std::ios_base::end); - size_t strings_len = (off_t)file.tellg() - oldpos; - file.seekg(oldpos, std::ios_base::beg); - - messages.flags(std::ios::dec); - messages << "strings: " << strings_len << " bytes at 0x"; - messages.flags(std::ios::hex); - messages << file.tellg() << "\n"; - - vector symbolStrings; - // Note: len + 1 for a nul terminator, for safety. - symbolStrings.resize(strings_len + 1); - file.read(&symbolStrings[0], strings_len); - if ((size_t)file.gcount() != strings_len) { - messages << "Failed to read all strings.\n"; - return false; - } - - assert(sizeof(struct aout_symbol) == 12); - - int nsymbols = 0; - - struct aout_symbol* aout_symbol_ptr = (struct aout_symbol *) (void*) &symbolData[0]; - int n_symbols = symbsize / sizeof(struct aout_symbol); - for (int i = 0; i < n_symbols; i++) { - uint32_t index = unencode32((unsigned char*)&aout_symbol_ptr[i].strindex, endianness); - uint32_t type = unencode32((unsigned char*)&aout_symbol_ptr[i].type, endianness); - uint32_t addr = unencode32((unsigned char*)&aout_symbol_ptr[i].addr, endianness); - - // TODO: These bits probably mean different things for - // different a.out formats. For OpenBSD/m88k at least, - // this bit (0x01000000) seems to mean "a normal symbol". - if (!(type & 0x01000000)) - continue; - - // ... and the rectangle drawing demo says - // "_my_memset" at addr 1020, type 5020000 - // "rectangles_m88k_O2.o" at addr 1020, type 1f000000 - if ((type & 0x1f000000) == 0x1f000000) - continue; - - if (index >= (uint32_t)strings_len) { - messages << "symbol " << i << " has invalid string index\n"; - continue; - } - - string symbol = ((char*) &symbolStrings[0]) + index; - if (symbol == "") - continue; - - // messages << "\"" << symbol << "\" at addr " << addr - // << ", type " << type << "\n"; - - // Add this symbol to the symbol registry: - symbolRegistry->AddSymbol(symbol, addr); - ++ nsymbols; - } - - messages.flags(std::ios::dec); - messages << nsymbols << " symbols read\n"; - } - - // Set the CPU's entry point. - stringstream ss; - ss << (int64_t)(int32_t)entry; - component->SetVariableValue("pc", ss.str()); - - return true; -} - - -/*****************************************************************************/ - - -#ifdef WITHUNITTESTS - -#include "ComponentFactory.h" - -static void Test_FileLoader_aout_Constructor() -{ - FileLoader_aout aoutLoader("test/FileLoader_A.OUT_M88K"); -} - -UNITTESTS(FileLoader_aout) -{ - UNITTEST(Test_FileLoader_aout_Constructor); - - // TODO -} - -#endif diff -Nru gxemul-0.6.2/src/main/fileloaders/FileLoader_bout.cc gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_bout.cc --- gxemul-0.6.2/src/main/fileloaders/FileLoader_bout.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_bout.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2009-2019 Anders Gavare. 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -using std::setw; -using std::setfill; -using std::ifstream; - -#include "AddressDataBus.h" -#include "components/CPUComponent.h" -#include "FileLoader_bout.h" - -#include "thirdparty/exec_bout.h" - - -FileLoader_bout::FileLoader_bout(const string& filename) - : FileLoaderImpl(filename) -{ -} - - -string FileLoader_bout::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const -{ - matchness = 0.9; - - if (buflen >= 0x2c && buf[0] == 0x0d && buf[1] == 0x01 && buf[2] == 0x00 && buf[3] == 0x00) { - return "b.out_i960_little"; - } - - if (buflen >= 0x2c && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 && buf[3] == 0x0d) { - return "b.out_i960_big"; - } - - matchness = 0.0; - return ""; -} - - -static uint32_t unencode32(uint8_t *p, Endianness endianness) -{ - uint32_t res; - - if (endianness == BigEndian) - res = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24); - else - res = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); - - return res; -} - - -bool FileLoader_bout::LoadIntoComponent(refcount_ptr component, ostream& messages) const -{ - AddressDataBus* bus = component->AsAddressDataBus(); - if (bus == NULL) { - messages << "Target is not an AddressDataBus.\n"; - return false; - } - - ifstream file(Filename().c_str()); - if (!file.is_open()) { - messages << "Unable to read file.\n"; - return false; - } - - unsigned char buf[65536]; - - memset(buf, 0, sizeof(buf)); - file.seekg(0, std::ios_base::end); - uint64_t totalSize = file.tellg(); - file.seekg(0, std::ios_base::beg); - file.read((char *)buf, totalSize < sizeof(buf)? totalSize : sizeof(buf)); - size_t amountRead = file.gcount(); - - float matchness; - string format = DetectFileType(buf, amountRead, matchness); - - if (format == "") { - messages << "Unknown b.out format.\n"; - return false; - } - - file.seekg(0, std::ios_base::beg); - - StateVariable* var = component->GetVariable("bigendian"); - if (var == NULL) { - messages << "Target does not have the 'bigendian' variable," - " which is needed to\n" - "load b.out files.\n"; - return false; - } - - Endianness endianness = LittleEndian; - if (format == "b.out_i960_big") - endianness = BigEndian; - - struct bout_exec header; - uint32_t entry; - - file.read((char *)&header, sizeof(header)); - if (file.gcount() != sizeof(header)) { - messages << "The file is too small to be a b.out.\n"; - return false; - } - - entry = unencode32((unsigned char*)&header.a_entry, endianness); - - uint32_t textaddr = unencode32((unsigned char*)&header.a_tload, endianness); - uint32_t textsize = unencode32((unsigned char*)&header.a_text, endianness); - - uint32_t dataaddr = unencode32((unsigned char*)&header.a_dload, endianness); - uint32_t datasize = unencode32((unsigned char*)&header.a_data, endianness); - - // int32_t symbsize = unencode32((unsigned char*)&header.a_syms, endianness); - - messages.flags(std::ios::hex); - messages << "b.out: entry point 0x"; - messages << setw(8) << setfill('0') << (uint32_t) entry << "\n"; - - messages.flags(std::ios::dec); - messages << "text + data = " << textsize << " + " << datasize << " bytes\n"; - - // Load text: - uint32_t vaddr = textaddr; - while (textsize != 0) { - int len = textsize > sizeof(buf) ? sizeof(buf) : textsize; - file.read((char *)buf, len); - len = file.gcount(); - if (len < 1) - break; - - // Write to the bus, one byte at a time. - for (int k=0; kAddressSelect(vaddr); - if (!bus->WriteData(buf[k])) { - messages.flags(std::ios::hex); - messages << "Failed to write data to virtual " - "address 0x" << vaddr << "\n"; - return false; - } - - ++ vaddr; - } - - textsize -= len; - } - - if (textsize != 0) { - messages << "Failed to read the entire file.\n"; - return false; - } - - // Load data: - vaddr = dataaddr; - while (datasize != 0) { - int len = datasize > sizeof(buf) ? sizeof(buf) : datasize; - file.read((char *)buf, len); - len = file.gcount(); - if (len < 1) - break; - - // Write to the bus, one byte at a time. - for (int k=0; kAddressSelect(vaddr); - if (!bus->WriteData(buf[k])) { - messages.flags(std::ios::hex); - messages << "Failed to write data to virtual " - "address 0x" << vaddr << "\n"; - return false; - } - - ++ vaddr; - } - - datasize -= len; - } - - if (datasize != 0) { - messages << "Failed to read the entire file.\n"; - return false; - } - -#if 0 - // TODO: Symbols. Similar to a.out? - - SymbolRegistry* symbolRegistry = NULL; - CPUComponent* cpu = component->AsCPUComponent(); - if (cpu != NULL) - symbolRegistry = &cpu->GetSymbolRegistry(); - - // Symbols: - if (symbolRegistry != NULL && symbsize > 0) { - messages.flags(std::ios::dec); - messages << "symbols: " << symbsize << " bytes at 0x"; - messages.flags(std::ios::hex); - messages << file.tellg() << "\n"; - - vector symbolData; - symbolData.resize(symbsize); - file.read(&symbolData[0], symbsize); - if (file.gcount() != symbsize) { - messages << "Failed to read all symbols.\n"; - return false; - } - - off_t oldpos = file.tellg(); - file.seekg(0, std::ios_base::end); - size_t strings_len = (off_t)file.tellg() - oldpos; - file.seekg(oldpos, std::ios_base::beg); - - messages.flags(std::ios::dec); - messages << "strings: " << strings_len << " bytes at 0x"; - messages.flags(std::ios::hex); - messages << file.tellg() << "\n"; - - vector symbolStrings; - // Note: len + 1 for a nul terminator, for safety. - symbolStrings.resize(strings_len + 1); - file.read(&symbolStrings[0], strings_len); - if (file.gcount() != strings_len) { - messages << "Failed to read all strings.\n"; - return false; - } - - assert(sizeof(struct aout_symbol) == 12); - - int nsymbols = 0; - - struct aout_symbol* aout_symbol_ptr = (struct aout_symbol *) (void*) &symbolData[0]; - int n_symbols = symbsize / sizeof(struct aout_symbol); - for (int i = 0; i < n_symbols; i++) { - uint32_t index = unencode32((unsigned char*)&aout_symbol_ptr[i].strindex, endianness); - uint32_t type = unencode32((unsigned char*)&aout_symbol_ptr[i].type, endianness); - uint32_t addr = unencode32((unsigned char*)&aout_symbol_ptr[i].addr, endianness); - - // TODO: These bits probably mean different things for - // different b.out formats. For OpenBSD/m88k at least, - // this bit (0x01000000) seems to mean "a normal symbol". - if (!(type & 0x01000000)) - continue; - - // ... and the rectangle drawing demo says - // "_my_memset" at addr 1020, type 5020000 - // "rectangles_m88k_O2.o" at addr 1020, type 1f000000 - if ((type & 0x1f000000) == 0x1f000000) - continue; - - if (index >= (uint32_t)strings_len) { - messages << "symbol " << i << " has invalid string index\n"; - continue; - } - - string symbol = ((char*) &symbolStrings[0]) + index; - if (symbol == "") - continue; - - // messages << "\"" << symbol << "\" at addr " << addr - // << ", type " << type << "\n"; - - // Add this symbol to the symbol registry: - symbolRegistry->AddSymbol(symbol, addr); - ++ nsymbols; - } - - messages.flags(std::ios::dec); - messages << nsymbols << " symbols read\n"; - } -#endif - - // Set the CPU's entry point. - stringstream ss; - ss << (int64_t)(int32_t)entry; - component->SetVariableValue("pc", ss.str()); - - return true; -} - - -/*****************************************************************************/ - - -#ifdef WITHUNITTESTS - -#include "ComponentFactory.h" - -static void Test_FileLoader_bout_Constructor() -{ - FileLoader_bout boutLoader("test/FileLoader_B.OUT_i960"); -} - -UNITTESTS(FileLoader_bout) -{ - UNITTEST(Test_FileLoader_bout_Constructor); - - // TODO -} - -#endif diff -Nru gxemul-0.6.2/src/main/fileloaders/FileLoader_ELF.cc gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_ELF.cc --- gxemul-0.6.2/src/main/fileloaders/FileLoader_ELF.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_ELF.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,618 +0,0 @@ -/* - * Copyright (C) 2008-2019 Anders Gavare. 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -using std::setw; -using std::setfill; -using std::ifstream; - -#include "AddressDataBus.h" -#include "components/CPUComponent.h" -#include "FileLoader_ELF.h" - -#include "thirdparty/exec_elf.h" - - -/* ELF machine types as strings: (same as exec_elf.h) */ -#define N_ELF_MACHINE_TYPES 244 -static const char *elf_machine_type[N_ELF_MACHINE_TYPES] = { - "NONE", "M32", "SPARC", "386", /* 0..3 */ - "68K", "88K", "486", "i860", /* 4..7 */ - "MIPS", "S370", "MIPS_RS3_LE", "RS6000", /* 8..11 */ - "unknown12", "unknown13", "unknown14", "PARISC", /* 12..15 */ - "NCUBE", "VPP500", "SPARC32PLUS", "i960", /* 16..19 */ - "PPC", "PPC64", "unknown22", "unknown23", /* 20..23 */ - "unknown24", "unknown25", "unknown26", "unknown27", /* 24..27 */ - "unknown28", "unknown29", "unknown30", "unknown31", /* 28..31 */ - "unknown32", "unknown33", "unknown34", "unknown35", /* 32..35 */ - "V800", "FR20", "RH32", "RCE", /* 36..39 */ - "ARM", "ALPHA", "SH", "SPARCV9", /* 40..43 */ - "TRICORE", "ARC", "H8_300", "H8_300H", /* 44..47 */ - "H8S", "H8_500", "IA_64", "MIPS_X", /* 48..51 */ - "COLDFIRE", "68HC12", "Fujitsu MMA", "Siemens PCP", /* 52..55 */ - "nCPU", "NDR1", "STARCORE", "ME16", /* 56..59 */ - "ST100", "TINYJ", "AMD64", "PDSP", /* 60..63 */ - "PDP10", "PDP11", "FX66", "ST9PLUS", /* 64..67 */ - "ST7", "68HC16", "68HC11", "68HC08", /* 68..71 */ - "68HC05", "SVX", "ST19", "VAX", /* 72..75 */ - "CRIS", "JAVELIN", "FIREPATH", "ZSP", /* 76..79 */ - "MMIX", "HUANY", "PRISM", "AVR", /* 80..83 */ - "FR30", "D10V", "D30V", "V850", /* 84..87 */ - "M32R", "MN10300", "MN10200", "picoJava", /* 88..91 */ - "OR1K", "ARC_A5", "Xtensa", "Alphamosaic VideoCore", /* 92..95 */ - "TMM_GPP", "NS32K", "TPC", "SNP1K", /* 96..99 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 100..103 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 104..107 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 108..111 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 112..115 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 116..119 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 120..123 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 124..127 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 128..131 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 132..135 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 136..139 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 140..143 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 144..147 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 148..151 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 152..155 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 156..159 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 160..163 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 164..167 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 168..171 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 172..175 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 176..179 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 180..183 */ - "unknown1xx", "unknown1xx", "unknown1xx", "TILE64", /* 184..187 */ - "TILEPro", "MicroBlaze", "unknown1xx", "unknown1xx", /* 188..191 */ - "TILE-GX", "unknown1xx", "unknown1xx", "unknown1xx", /* 192..195 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 196..199 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 200..203 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 204..207 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 208..211 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 212..215 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 216..219 */ - "Zilog Z80", "unknown1xx", "unknown1xx", "unknown1xx", /* 220..223 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 224..227 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 228..231 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 232..235 */ - "unknown1xx", "unknown1xx", "unknown1xx", "unknown1xx", /* 236..239 */ - "unknown1xx", "unknown1xx", "unknown1xx", "RISC-V", /* 240..243 */ -}; - - -FileLoader_ELF::FileLoader_ELF(const string& filename) - : FileLoaderImpl(filename) -{ -} - - -string FileLoader_ELF::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const -{ - if (buflen < sizeof(Elf32_Ehdr)) - return ""; - - // Note: The e_ident part of the 32-bit and the 64-bit variants have - // the same layout, so it is safe to only check the 32-bit variant here. - Elf32_Ehdr* elf32_ehdr = (Elf32_Ehdr*) buf; - if (elf32_ehdr->e_ident[EI_MAG0] == ELFMAG0 && - elf32_ehdr->e_ident[EI_MAG1] == ELFMAG1 && - elf32_ehdr->e_ident[EI_MAG2] == ELFMAG2 && - elf32_ehdr->e_ident[EI_MAG3] == ELFMAG3) { - // We are here if this is either an ELF32 or ELF64. - int elfClass = elf32_ehdr->e_ident[EI_CLASS]; - - matchness = 1.0; - if (elfClass == ELFCLASS32) - return "ELF32"; - if (elfClass == ELFCLASS64) - return "ELF64"; - - matchness = 0.0; - stringstream ss; - ss << "ELF Unknown class " << elfClass; - return ss.str(); - } - - return ""; -} - - -bool FileLoader_ELF::LoadIntoComponent(refcount_ptr component, ostream& messages) const -{ - AddressDataBus* bus = component->AsAddressDataBus(); - if (bus == NULL) { - messages << "Target is not an AddressDataBus.\n"; - return false; - } - - ifstream file(Filename().c_str()); - if (!file.is_open()) { - messages << "Unable to read file.\n"; - return false; - } - - char buf[64]; - - // buf must be large enough for the largest possible header we wish - // to examine to fit. - assert(sizeof(buf) >= sizeof(Elf32_Ehdr)); - assert(sizeof(buf) >= sizeof(Elf64_Ehdr)); - - memset(buf, 0, sizeof(buf)); - file.read(buf, sizeof(buf)); - - // Note: The e_ident part of the 32-bit and the 64-bit variants have - // the same layout, so it is safe to only use the 32-bit variant here. - Elf32_Ehdr* ehdr32 = (Elf32_Ehdr*) buf; - Elf64_Ehdr* ehdr64 = (Elf64_Ehdr*) buf; - if (ehdr32->e_ident[EI_MAG0] != ELFMAG0 || - ehdr32->e_ident[EI_MAG1] != ELFMAG1 || - ehdr32->e_ident[EI_MAG2] != ELFMAG2 || - ehdr32->e_ident[EI_MAG3] != ELFMAG3) { - messages << "Not an ELF.\n"; - return false; - } - - int elfClass = ehdr32->e_ident[EI_CLASS]; - int elfDataEncoding = ehdr32->e_ident[EI_DATA]; - int elfVersion = ehdr32->e_ident[EI_VERSION]; - - if (elfClass != ELFCLASS32 && elfClass != ELFCLASS64) { - messages << "Unknown ELF class.\n"; - return false; - } - if (elfDataEncoding != ELFDATA2LSB && elfDataEncoding != ELFDATA2MSB) { - messages << "Unknown ELF data encoding.\n"; - return false; - } - if (elfVersion != EV_CURRENT) { - messages << "Unknown ELF version.\n"; - return false; - } - - bool elf32 = elfClass == ELFCLASS32; - -#define ELF_HEADER_VAR(hdr32,hdr64,type,name) type name = elf32? hdr32->name \ - : hdr64->name; \ - if (elfDataEncoding == ELFDATA2LSB) { \ - int size = elf32? sizeof(hdr32->name) : sizeof(hdr64->name); \ - switch (size) { \ - case 2: name = LE16_TO_HOST(name); break; \ - case 4: name = LE32_TO_HOST(name); break; \ - case 8: name = LE64_TO_HOST(name); break; \ - } \ - } else { \ - int size = elf32? sizeof(hdr32->name) : sizeof(hdr64->name); \ - switch (size) { \ - case 2: name = BE16_TO_HOST(name); break; \ - case 4: name = BE32_TO_HOST(name); break; \ - case 8: name = BE64_TO_HOST(name); break; \ - } \ - } - - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_type); - - if (e_type != ET_EXEC) { - messages << "ELF file is not an Executable.\n"; - return false; - } - - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_entry); - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_machine); - - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_phoff); - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_phentsize); - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_phnum); - - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_shoff); - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_shentsize); - ELF_HEADER_VAR(ehdr32, ehdr64, uint64_t, e_shnum); - - size_t expectedPhentSize = (elf32? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr)); - if (e_phentsize != expectedPhentSize) { - messages << "Incorrect ELF phentsize? " << e_phentsize << ", should " - "be " << expectedPhentSize << "\n" - "Perhaps this is a dynamically linked " - "binary (which isn't supported yet).\n"; - return false; - } - - size_t expectedShentSize = (elf32? sizeof(Elf32_Shdr) : sizeof(Elf64_Shdr)); - if (e_shentsize != expectedShentSize) { - messages << "Incorrect ELF shentsize? " << e_shentsize << ", should " - "be " << expectedShentSize << "\n" - "Perhaps this is a dynamically linked " - "binary (which isn't supported yet).\n"; - return false; - } - - if (e_machine < N_ELF_MACHINE_TYPES) - messages << elf_machine_type[e_machine]; - else - messages << "machine type '" << e_machine << "'"; - messages << " ELF" << (elf32? 32 : 64) << " "; - - messages << (elfDataEncoding == ELFDATA2LSB? "LSB (LE)" : "MSB (BE)") << ": "; - - if (!elf32 && (e_machine == EM_PPC || e_machine == EM_PPC64)) - messages << "PPC function descriptor at"; - else - messages << "entry point"; - - messages << " 0x"; - messages.flags(std::ios::hex); - - // Special case for MIPS: 32-bit addresses are sign-extended. - if (e_machine == EM_MIPS && elf32) - e_entry = (int32_t) e_entry; - - uint64_t display_entry_point = e_entry; - - // MIPS16 encoding (16-bit words) is indicated by the lowest bit of the PC. - bool mips16 = false; - if (e_machine == EM_MIPS && (e_entry & 1)) { - display_entry_point &= ~1; - mips16 = true; - } - - // SHmedia (SH64) 32-bit encoding is indicated by the lowest bit of the PC. - bool shmedia = false; - if (e_machine == EM_SH && (e_entry & 1)) { - display_entry_point &= ~1; - shmedia = true; - } - - if (elf32) - messages << setw(8) << setfill('0') << (uint32_t) display_entry_point; - else - messages << setw(16) << setfill('0') << (uint64_t) display_entry_point; - - if (mips16) - messages << " (MIPS16 encoding)"; - - if (shmedia) - messages << " (SHmedia encoding)"; - - messages << "\n"; - - // PROGRAM HEADERS - size_t i; - for (i=0; i= sizeof(Elf32_Phdr)); - assert(sizeof(phdr_buf) >= sizeof(Elf64_Phdr)); - Elf32_Phdr* phdr32 = (Elf32_Phdr*) phdr_buf; - Elf64_Phdr* phdr64 = (Elf64_Phdr*) phdr_buf; - - memset(phdr_buf, 0, sizeof(phdr_buf)); - - int toRead = elf32? sizeof(Elf32_Phdr) : sizeof(Elf64_Phdr); - file.read(phdr_buf, toRead); - if (file.gcount() != toRead) { - messages << "Unable to read Phdr.\n"; - return false; - } - - ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_type); - ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_offset); - ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_vaddr); - ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_filesz); - ELF_HEADER_VAR(phdr32, phdr64, uint64_t, p_memsz); - - // Skip non-loadable program segments: - if (p_type != PT_LOAD) - continue; - - if (p_memsz < p_filesz) { - messages << "memsz < filesz. TODO: how" - " to handle this? memsz = " << p_memsz << - ", filesz = " << p_filesz << "\n"; - return false; - } - - // Special case for MIPS: 32-bit addresses are sign-extended. - if (e_machine == EM_MIPS && elf32) - p_vaddr = (int32_t) p_vaddr; - - messages.flags(std::ios::hex); - messages << "loadable chunk: vaddr 0x"; - - if (elf32) - messages << setw(8) << setfill('0') << (uint32_t) p_vaddr; - else - messages << setw(16) << setfill('0') << (uint64_t) p_vaddr; - - messages.flags(std::ios::dec); - messages << ", " << p_filesz << " bytes\n"; - - file.seekg(p_offset, std::ios::beg); - char databuf[65536]; - uint64_t bytesRead = 0; - uint64_t vaddrToWriteTo = p_vaddr; - - while (bytesRead < p_filesz) { - int sizeToRead = sizeof(databuf); - if (sizeToRead + bytesRead > p_filesz) - sizeToRead = p_filesz - bytesRead; - - assert(sizeToRead != 0); - memset(databuf, 0, sizeToRead); - - file.read(databuf, sizeToRead); - int bytesReadThisTime = file.gcount(); - bytesRead += bytesReadThisTime; - - // Write to the bus, one byte at a time. - for (int k=0; kAddressSelect(vaddrToWriteTo); - if (!bus->WriteData(databuf[k])) { - messages.flags(std::ios::hex); - messages << "Failed to write data to " - "virtual address 0x" - << vaddrToWriteTo << "\n"; - return false; - } - - ++ vaddrToWriteTo; - } - } - } - - // SECTION HEADERS - vector symtab; - vector symstrings; - for (i=0; i= sizeof(Elf32_Shdr)); - assert(sizeof(shdr_buf) >= sizeof(Elf64_Shdr)); - Elf32_Shdr* shdr32 = (Elf32_Shdr*) shdr_buf; - Elf64_Shdr* shdr64 = (Elf64_Shdr*) shdr_buf; - - memset(shdr_buf, 0, sizeof(shdr_buf)); - - int toRead = elf32? sizeof(Elf32_Shdr) : sizeof(Elf64_Shdr); - file.read(shdr_buf, toRead); - if (file.gcount() != toRead) { - messages << "Unable to read Shdr.\n"; - return false; - } - - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_name); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_type); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_flags); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_addr); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_offset); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_size); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_link); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_info); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_addralign); - ELF_HEADER_VAR(shdr32, shdr64, uint64_t, sh_entsize); - - if (sh_type == SHT_SYMTAB) { - if (symtab.size() > 0) { - messages << "symtab: another symtab already loaded? TODO\n"; - return false; - } - - int entrySize = elf32? sizeof(Elf32_Sym) : sizeof(Elf64_Sym); - int nEntries = sh_size / entrySize; - - messages.flags(std::ios::dec); - messages << "symtab: " << nEntries << " symbols at 0x"; - messages.flags(std::ios::hex); - messages << sh_offset << "\n"; - - symtab.resize(sh_size); - file.seekg(sh_offset, std::ios::beg); - file.read(&symtab[0], sh_size); - if ((uint64_t) file.gcount() != sh_size) { - messages << "Failed to read all " << sh_size << " symbol bytes.\n"; - return false; - } - } - - // TODO/HACK: Figure out which strtab to use. For now, simply - // use the largest one! - if (sh_type == SHT_STRTAB && sh_size > symstrings.size()) { - messages.flags(std::ios::dec); - messages << "strtab: " << sh_size << " bytes at 0x"; - messages.flags(std::ios::hex); - messages << sh_offset << "\n"; - - symstrings.resize(sh_size); - file.seekg(sh_offset, std::ios::beg); - file.read(&symstrings[0], sh_size); - if ((uint64_t) file.gcount() != sh_size) { - messages << "Failed to read all " << sh_size << " symbol string bytes.\n"; - return false; - } - } - } - - SymbolRegistry* symbolRegistry = NULL; - CPUComponent* cpu = component->AsCPUComponent(); - if (cpu != NULL) - symbolRegistry = &cpu->GetSymbolRegistry(); - - // Symbols - if (symbolRegistry != NULL && symtab.size() > 0 && symstrings.size() > 0) { - int entrySize = elf32? sizeof(Elf32_Sym) : sizeof(Elf64_Sym); - int nEntries = symtab.size() / entrySize; - - // For safety: - symstrings.resize(symstrings.size() + 1); - symstrings[symstrings.size() - 1] = '\0'; - - int nsymbols = 0; - - messages.flags(std::ios::hex); - - for (int j=0; j= symstrings.size() - 1) { - messages << "symbol pointer mismatch?\n"; - continue; - } - - string symbol = &symstrings[st_name]; - - // Special case for MIPS: 32-bit addresses are sign-extended. - if (e_machine == EM_MIPS && elf32) - st_value = (int32_t) st_value; - - // Special case for MIPS: _gp symbol initiates the GP register. - if (e_machine == EM_MIPS && symbol == "_gp") { - messages << "found _gp address: 0x"; - if (elf32) - messages << setw(8) << setfill('0') << (uint32_t) st_value << "\n"; - else - messages << setw(16) << setfill('0') << (uint64_t) st_value << "\n"; - - stringstream ss; - ss << st_value; - component->SetVariableValue("gp", ss.str()); - } - - // FOR DEBUGGING ONLY: - //messages << "symbol name '" << symbol << "', addr 0x" << - // st_value << ", size 0x" << st_size << "\n"; - - // Add this symbol to the symbol registry: - symbolRegistry->AddSymbol(symbol, st_value); - ++ nsymbols; - } - - messages.flags(std::ios::dec); - messages << nsymbols << " symbols read\n"; - } - - // Set the CPU's entry point. - -#if 0 - if (elf64 && arch == ARCH_PPC) { - /* - * Special case for 64-bit PPC ELFs: - * - * The ELF starting symbol points to a ".opd" section - * which contains a function descriptor: - * - * uint64_t start; - * uint64_t toc_base; - * uint64_t something_else; (?) - */ - int res; - unsigned char b[sizeof(uint64_t)]; - uint64_t toc_base; - - debug("PPC64: "); - - res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry, b, - sizeof(b), MEM_READ, NO_EXCEPTIONS); - if (!res) - debug(" [WARNING: could not read memory?] "); - - /* PPC are always big-endian: */ - *entrypointp = ((uint64_t)b[0] << 56) + - ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + - ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + - ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + - (uint64_t)b[7]; - - res = m->cpus[0]->memory_rw(m->cpus[0], mem, eentry + 8, - b, sizeof(b), MEM_READ, NO_EXCEPTIONS); - if (!res) - fatal(" [WARNING: could not read memory?] "); - - toc_base = ((uint64_t)b[0] << 56) + - ((uint64_t)b[1] << 48) + ((uint64_t)b[2] << 40) + - ((uint64_t)b[3] << 32) + ((uint64_t)b[4] << 24) + - ((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + - (uint64_t)b[7]; - - debug("entrypoint 0x%016"PRIx64", toc_base 0x%016"PRIx64"\n", - (uint64_t) *entrypointp, (uint64_t) toc_base); - if (tocp != NULL) - *tocp = toc_base; - } -#endif - - stringstream ss; - ss << e_entry; - component->SetVariableValue("pc", ss.str()); - component->SetVariableValue("bigendian", - elfDataEncoding == ELFDATA2LSB? "false" : "true"); - - return true; -} - - -/*****************************************************************************/ - - -#ifdef WITHUNITTESTS - -#include "ComponentFactory.h" - -static void Test_FileLoader_ELF_Constructor() -{ - FileLoader_ELF elfLoader("test/FileLoader_ELF_MIPS"); -} - -UNITTESTS(FileLoader_ELF) -{ - UNITTEST(Test_FileLoader_ELF_Constructor); - - // TODO -} - -#endif diff -Nru gxemul-0.6.2/src/main/fileloaders/FileLoader_raw.cc gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_raw.cc --- gxemul-0.6.2/src/main/fileloaders/FileLoader_raw.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/fileloaders/FileLoader_raw.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2009-2010 Anders Gavare. 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -using std::setw; -using std::setfill; -using std::ifstream; - -#include "AddressDataBus.h" -#include "components/CPUComponent.h" -#include "FileLoader_raw.h" -#include "StringHelper.h" - - -FileLoader_raw::FileLoader_raw(const string& filename) - : FileLoaderImpl(filename) -{ -} - - -string FileLoader_raw::DetectFileType(unsigned char *buf, size_t buflen, float& matchness) const -{ - matchness = 0.0; - - vector parts = StringHelper::SplitStringIntoVector(Filename(), ':'); - - // Possible variants: - // - // filename <-- NOT a raw file - // raw:vaddr:filename - // raw:vaddr:skiplen:filename - // raw:vaddr:skiplen:initialpc:filename e.g. raw:0xbfc00000:0x100:0xbfc00884:rom.bin - if (parts.size() < 3) - return ""; - - if (parts[0] != "raw") - return ""; - - matchness = 1.0; - return "raw"; -} - - -bool FileLoader_raw::LoadIntoComponent(refcount_ptr component, ostream& messages) const -{ - AddressDataBus* bus = component->AsAddressDataBus(); - if (bus == NULL) { - messages << "Target is not an AddressDataBus.\n"; - return false; - } - - // Possible variants: - // - // raw:vaddr:filename - // raw:vaddr:skiplen:filename - // raw:vaddr:skiplen:initialpc:filename e.g. 0xbfc00000:0x100:0xbfc00884:rom.bin - vector parts = StringHelper::SplitStringIntoVector(Filename(), ':'); - if (parts.size() < 3 || parts.size() > 5) { - messages << "Syntax is raw:vaddr:[skiplen:[initialpc:]]filename.\n"; - return false; - } - - string strvaddr = parts[1]; - string strskiplen = (parts.size() >= 4)? parts[2] : ""; - string strinitialpc = (parts.size() >= 5)? parts[3] : ""; - string fname = parts[parts.size() - 1]; - - bool error; - uint64_t vaddr = StringHelper::ParseNumber(strvaddr.c_str(), error); - if (error) { - messages << "could not parse vaddr.\n"; - return false; - } - - uint64_t skiplen = 0; - if (strskiplen != "") { - skiplen = StringHelper::ParseNumber(strskiplen.c_str(), error); - if (error) { - messages << "could not parse skiplen\n"; - return false; - } - } - - uint64_t initialpc = vaddr; - if (strinitialpc != "") { - initialpc = StringHelper::ParseNumber(strinitialpc.c_str(), error); - if (error) { - messages << "could not parse initialpc\n"; - return false; - } - } - - ifstream file(fname.c_str()); - if (!file.is_open()) { - messages << "Unable to read file.\n"; - return false; - } - - file.seekg(0, std::ios_base::end); - off_t totalSize = file.tellg(); - file.seekg(skiplen, std::ios_base::beg); - totalSize -= skiplen; - - // Read everything: - vector data; - data.resize(totalSize); - file.read(&data[0], totalSize); - if (file.gcount() != totalSize) { - messages << "failed to read the whole file\n"; - return false; - } - - messages.flags(std::ios::hex); - messages << "Raw file: entry point 0x" << initialpc << "\n"; - messages << "loadable chunk"; - if (skiplen != 0) { - messages.flags(std::ios::dec); - messages << " at offset " << skiplen; - } - - messages.flags(std::ios::hex); - messages << ": vaddr 0x" << vaddr; - - messages.flags(std::ios::dec); - messages << ", " << totalSize << " bytes\n"; - - // Write to the bus, one byte at a time. - for (size_t k=0; k<(size_t)totalSize; ++k) { - bus->AddressSelect(vaddr); - if (!bus->WriteData(data[k])) { - messages.flags(std::ios::hex); - messages << "Failed to write data to " - "virtual address 0x" << vaddr << "\n"; - return false; - } - - ++ vaddr; - } - - // Set the CPU's entry point. - stringstream ss; - ss << initialpc; - component->SetVariableValue("pc", ss.str()); - - return true; -} - - -/*****************************************************************************/ - - -#ifdef WITHUNITTESTS - -#include "ComponentFactory.h" - -static void Test_FileLoader_raw_Constructor() -{ - // TODO: haha, better test. - FileLoader_raw rawLoader("test/FileLoader_A.OUT_M88K"); -} - -UNITTESTS(FileLoader_raw) -{ - UNITTEST(Test_FileLoader_raw_Constructor); - - // TODO -} - -#endif diff -Nru gxemul-0.6.2/src/main/fileloaders/Makefile.skel gxemul-0.7.0+dfsg/src/main/fileloaders/Makefile.skel --- gxemul-0.6.2/src/main/fileloaders/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/fileloaders/Makefile.skel 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -# -# Makefile for GXemul src/main/fileloaders -# - -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) -LIBS=$(OTHERLIBS) - -OBJS=FileLoader_aout.o FileLoader_bout.o FileLoader_ELF.o FileLoader_raw.o - -all: $(OBJS) - -$(OBJS): Makefile - -clean: - rm -f $(OBJS) - -clean_all: clean - rm -f Makefile - diff -Nru gxemul-0.6.2/src/main/GXemul.cc gxemul-0.7.0+dfsg/src/main/GXemul.cc --- gxemul-0.6.2/src/main/GXemul.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/GXemul.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,1159 +0,0 @@ -/* - * Copyright (C) 2003-2019 Anders Gavare. 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. The name of the author 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. - * - * - * This file contains two things: - * - * 1. Doxygen documentation for the general design concepts of the - * emulator. The mainpage documentation written here ends up on - * the "main page" in the generated HTML documentation. - * - * 2. The GXemul class implementation. - */ - - -/*! \mainpage Source code documentation - * - * \section intro_sec Introduction - * - * This is the automatically generated Doxygen documentation for %GXemul, - * built from comments throughout the source code. - * - * See the main documentation for more - * information about this version of %GXemul. - * - * See GXemul's home page for more information about %GXemul in general: - * http://gavare.se/gxemul/ - * - * NOTE: There is a huge portion of code in - * %GXemul which is legacy code. The documentation you will find on this page - * is only about the new framework, which is still being developed. - * - * The main program creates a GXemul instance, and does one of two things: - *
      - *
    • Starts without any template %machine. (-V) - *
    • Starts with a template %machine, and a list of additional - * components and files - * to attempt to attach (usually kernel binary to boot in the - * emulated %machine). - *
    - * - * After letting the %GXemul instance load the files (or, in the more general - * case, attach the components), GXemul::Run() is called. - * This is the main loop. It doesn't really do much, it simply calls the UI's - * main loop, i.e. ConsoleUI::MainLoop(). - * - * Most of the source code in %GXemul centers around a few core concepts. - * An overview of these concepts are given below. Anyone who wishes to - * delve into the source code should be familiar with them. - * - * - * \section concepts_sec Core concepts - * - * See the end-user description of the framework - * for information about how these concepts appear to the actual user. The - * sections below describe how those concepts are implemented in the code. - * - * \subsection components_subsec Components - * - * The most important core concept in %GXemul is the Component. Examples of - * components are processors, networks interface cards, video displays, RAM - * %memory, busses, %interrupt controllers, and all other kinds of devices. - * - * Each component has a parent, so the full set of components in an emulation - * are in fact a tree. A GXemul instance has one such tree. The root - * component is a special RootComponent, which holds some basic state about - * the emulation, such as the number of steps executed. - * It also contains zero or more sub-components. - * - *
    - * - * Starting from the root node, each component has a path, e.g. - * root.machine1.mainbus0.ram0 for the RAM component in machine1 - * in the example above. - * - * The state of each component is stored within that component. The state - * consists of a number of variables (see StateVariable) such as strings, - * integers, bools, and other more high-level types such as zero-filled %memory - * arrays. Such %memory arrays are used e.g. by the RAMComponent to emulate - * RAM, and can also be used to emulate video framebuffer %memory. - * - * Individual components are implemented in src/components/, with - * header files in src/include/components/. The configure - * script looks for the string COMPONENT(name) in the header files, - * and automagically adds those to the list of components that will be - * available at runtime. In addition, make documentation also builds - * HTML pages with lists of available - * components, and as a special case, - * a list of available - * template machines (because they have - * special meaning to the end-user). - * - * \subsection commandinterpreter_subsec Command interpreter - * - * A GXemul instance has a CommandInterpreter, which is the part that parses a - * command line, figures out which Command is to be executed, and executes it. - * The %CommandInterpreter can be given a complete command line as a string, or - * it can be given one character (or keypress) at a time. In the later case, - * the TAB key either completes the word currently being written, or writes - * out a list of possible completions. - * - * The %CommandInterpreter, via the ConsoleUI, is the user interface as seen - * by the user. - * - * \subsection unittest_subsec Unit tests - * - * Wherever it makes sense, unit tests should be written to make sure - * that the code is correct, and stays correct. The UnitTest class contains - * static helper functions for writing unit tests, such as UnitTest::Assert. - * To add unit tests to a class, the class should be UnitTestable, and in - * particular, it should implement UnitTestable::RunUnitTests by using the - * UNITTESTS(className) macro. Individual test cases are then called, as - * static non-member functions, using the UNITTEST(testname) macro. - * - * Since test cases are non-member functions, they need to create instances - * of the class they wish to test, and they can only call public member - * functions on those objects, not private ones. Thus, the unit tests only - * test the "public API" of all classes. (If the internal API needs to be - * tested, then a workaround can be to add a ConsistencyCheck member function - * which is public, but mentioning in the documentation for that function - * that it is only meant for internal use and debugging.) - * - * Unit tests are normally executed by make test. This is implicitly - * done when doing make install as well. - * - * It is recommended to run the configure script with the - * --debug option during development; among other things, this enables - * use of Wu Yongwei's new/debug %memory - * leak detector (part of - * Stones of NVWA). - */ - - -/*****************************************************************************/ - -#include "ConsoleUI.h" -#include "NullUI.h" - -#include "GXemul.h" -#include "components/RootComponent.h" -#include "ComponentFactory.h" -#include "UnitTest.h" - -#include -#include -#include -#include -#include -#include -#include - - -GXemul::GXemul() - : m_quietMode(false) - , m_ui(new NullUI(this)) - , m_commandInterpreter(this) - , m_runState(Paused) - , m_interrupting(false) - , m_nrOfSingleStepsLeft(1) - , m_rootComponent(new RootComponent(this)) - , m_snapshottingEnabled(false) -{ - gettimeofday(&m_lastOutputTime, NULL); - m_lastOutputStep = 0; - - ClearEmulation(); -} - - -void GXemul::ClearEmulation() -{ - if (GetRunState() == Running) - SetRunState(Paused); - - m_rootComponent = new RootComponent(this); - m_emulationFileName = ""; - - GetUI()->UpdateUI(); -} - - -bool GXemul::IsTemplateMachine(const string& templateName) const -{ - string nameWithoutArgs = templateName; - size_t p = nameWithoutArgs.find('('); - if (p > 0) - nameWithoutArgs = templateName.substr(0, p); - - if (!ComponentFactory::HasAttribute(nameWithoutArgs, "template")) - return false; - - if (!ComponentFactory::HasAttribute(nameWithoutArgs, "machine")) - return false; - - return true; -} - - -bool GXemul::CreateEmulationFromTemplateMachine(const string& templateName) -{ - if (!IsTemplateMachine(templateName)) { - std::cerr << templateName << " is not a known template machine name.\n" - "Use gxemul -H to get a list of valid machine templates.\n"; - return false; - } - - refcount_ptr machine = - ComponentFactory::CreateComponent(templateName, this); - if (machine.IsNULL()) - return false; - - GetRootComponent()->AddChild(machine); - return true; -} - - -void GXemul::ListTemplates() -{ - std::cout << "Available template machines:\n\n"; - - vector names = ComponentFactory::GetAllComponentNames(true); - - size_t maxNameLen = 0; - for (size_t i=0; i maxNameLen) - maxNameLen = names[i].length(); - - for (size_t i=0; i component = - ComponentFactory::CreateComponent(machineName); - - if (!component.IsNULL() && - component->GetChildren().size() != 0) - std::cout << "
    " <<
    -		    component->GenerateTreeDump("", true, "../")
    -		    << "
    "; -} - - -void GXemul::GenerateHTMLListOfComponents(bool machines) -{ - std::cout << - "Available " << - (machines? "template machines" : "components") << ":\n" - "

    \n" - "\n" - " \n"; - if (machines) - std::cout << " \n"; - std::cout << - " \n" - " \n" - " \n" - "\n"; - - bool everyOther = false; - vector names = ComponentFactory::GetAllComponentNames(false); - for (size_t i=0; i creatable = - ComponentFactory::CreateComponent(componentName); - if (creatable.IsNULL()) - continue; - - bool isTemplateMachine = !ComponentFactory::GetAttribute( - componentName, "machine").empty() && - !ComponentFactory::GetAttribute( - componentName, "template").empty(); - - if (machines) { - if (!isTemplateMachine) - continue; - } else { - // Other components: Don't include template machines. - if (isTemplateMachine) - continue; - } - - // Include an ASCII tree dump for template components that - // have children: - if (!ComponentFactory::GetAttribute( - componentName, "template").empty()) { - refcount_ptr component = - ComponentFactory::CreateComponent(componentName); - - if (!component.IsNULL() && - component->GetChildren().size() != 0) - treeDump = "
    " +
    -				    component->GenerateTreeDump("", true)
    -				    + "
    "; - } - - // Some distance between table entries: - std::cout << - "
    \n" - " " - "\n"; - - std::cout << - "\n"; - - // Include a href link to a "full html page" for a component, - // if it exists: - std::ifstream documentationComponentFile(( - "doc/components/component_" - + componentName + ".html").c_str()); - std::ifstream documentationMachineFile(( - "doc/machines/machine_" - + componentName + ".html").c_str()); - - if (documentationComponentFile.is_open()) - std::cout << - " \n"; - else if (documentationMachineFile.is_open()) - std::cout << - " \n"; - else - std::cout << - " \n"; - - if (machines) { - // Include an img and a href link to a screenshot for a component, - // if it exists: - std::ifstream screenshotThumbFile(( - "doc/machines/machine_" - + componentName + "-thumb.png").c_str()); - std::ifstream screenshotLargeFile(( - "doc/machines/machine_" - + componentName + ".png").c_str()); - - std::cout << " \n"; - } - - std::cout << - " \n" - " \n" - " \n" - "\n"; - - everyOther = !everyOther; - } - - std::cout << "
    " << - (machines? "Machine name" : "Component name") << ":" - "  Screenshot:  Description:  Comments:  Contributors:  
    " - "" << componentName << - "" - "" << componentName << - "" << componentName - << ""; - - if (screenshotLargeFile.is_open()) - std::cout << ""; - - if (screenshotThumbFile.is_open()) - std::cout << ""; - else if (screenshotLargeFile.is_open()) - std::cout << "(screenshot)"; - - if (screenshotLargeFile.is_open()) - std::cout << ""; - - std::cout << "" << ComponentFactory::GetAttribute( - componentName, "description") << - treeDump << "" << ComponentFactory::GetAttribute( - componentName, "comments") << "" << ComponentFactory::GetAttribute( - componentName, "contributors") << "

    \n"; -} - - -bool GXemul::ParseFilenames(string templateMachine, int filenameCount, char *filenames[]) -{ - bool optionsEnoughToStartRunning = false; - - if (templateMachine != "") { - if (CreateEmulationFromTemplateMachine(templateMachine)) { - // A template is now being used. - } else { - std::cerr << "Failed to create configuration from " - "template: " << templateMachine << "\n" << - "Aborting." << "\n"; - return false; - } - } - - // 1. If a machine template has been selected, then treat the following - // arguments as arguments to the 'add' command. - // - // 2. Otherwise, treat the argument as a configuration file. - - if (filenameCount > 0) { - if (templateMachine != "") { - // Machine template. - while (filenameCount > 0) { - stringstream cmd; - - // TODO: Different syntax! - // Use "add" with different syntax here... - - cmd << "load " << filenames[0] - << " root.machine0.mainbus0.cpu0"; - - // TODO: Get rid of this onReset mechanism! - m_onResetCommands.push_back(cmd.str()); - - filenameCount --; - filenames ++; - } - - optionsEnoughToStartRunning = true; - } else { - // Config file. - if (filenameCount == 1) { - string configfileName = filenames[0]; - optionsEnoughToStartRunning = true; - - string cmd = "load " + configfileName; - m_onResetCommands.push_back(cmd); - } else { - std::cerr << "More than one configfile name " - "supplied on the command line?" << "\n" << - "Aborting." << "\n"; - return false; - } - } - } - - if (optionsEnoughToStartRunning) { - return true; - } else { - if (templateMachine != "") { - if (GetRunState() == Paused) - return true; - - std::cerr << - "No binary specified. Usually when starting up an emulation based on a template\n" - "machine, you need to supply one or more binaries. This could be an operating\n" - "system kernel, a ROM image, or something similar.\n" - "\n" - "You can also use the -V option to start in paused mode, and load binaries\n" - "interactively.\n" - "\n" - "(Run gxemul -h for more help on command line options.)\n"; - return false; - } - - PrintUsage(); - return false; - } -} - - -string GXemul::Version() -{ - stringstream ss; - ss << "GXemul " -#ifdef VERSION - << VERSION -#else - << "(unknown version)" -#endif - << " " COPYRIGHT_MSG"\n" SECONDARY_MSG; - - return ss.str(); -} - - -void GXemul::PrintUsage() const -{ - std::cout << Version() << "\n"; - - std::cout << "Insufficient command line arguments given to" - " start an emulation. You have\n" - "the following alternatives:\n" << - "\n" << - " 1. Run gxemul with the machine selection option " - "(-e), which creates\n" - " a default emulation from a template machine.\n\n" - " 2. Run gxemul with a configuration file (.gxemul).\n" - " This is useful for more complicated setups.\n\n" - " 3. Run gxemul -V with no other options, which causes" - " gxemul to be started\n" - " with no emulation loaded at all.\n\n" << - "\n" << - "Run gxemul -h for help on command line options.\n\n"; -} - - -void GXemul::InitUI() -{ - // Default to the console UI: - m_ui = new ConsoleUI(this); - - // Once a GUI has been implemented, this is the - // place to call its constructor. TODO - - GetUI()->Initialize(); -} - - -int GXemul::Run() -{ - // Not really running yet: - RunState savedRunState = GetRunState(); - SetRunState(Paused); - - if (!GetQuietMode()) { - GetUI()->ShowStartupBanner(); - - // Dump (a suitable part of) the configuration tree at startup. - const Component* component = GetRootComponent(); - if (component->GetChildren().size() > 0) { - while (true) { - int nChildren = component->GetChildren().size(); - if (nChildren == 0 || nChildren > 1) - break; - - component = component->GetChildren()[0]; - } - - GetUI()->ShowDebugMessage(component->GenerateTreeDump("") + "\n"); - } - } - - if (!Reset()) { - GetUI()->ShowDebugMessage("Aborting.\n"); - return 1; - } - - if (!GetQuietMode()) { - // A separator line, if we start emulating directly without dropping - // into the interactive debugger. (To mimic pre-0.6.0 appearance.) - if (savedRunState == Running) - GetUI()->ShowDebugMessage("--------------------------------" - "-----------------------------------------------\n\n"); - } - - SetRunState(savedRunState); - - - try { - GetUI()->MainLoop(); - } catch (std::exception& ex) { - stringstream ss; - ss << "\n### FATAL ERROR ###\n\n" << ex.what() << "\n\n" << - "If you are able to reproduce this crash, " - "please send detailed repro-steps to\n" - "the author, to the gxemul-devel mailing list, or" - " ask in #GXemul on the\n" - "FreeNode IRC network.\n"; - - GetUI()->FatalError(ss.str()); - - return 1; - } - - return 0; -} - - -const string& GXemul::GetEmulationFilename() const -{ - return m_emulationFileName; -} - - -void GXemul::SetEmulationFilename(const string& filename) -{ - m_emulationFileName = filename; - - GetUI()->UpdateUI(); -} - - -CommandInterpreter& GXemul::GetCommandInterpreter() -{ - return m_commandInterpreter; -} - - -uint64_t GXemul::GetStep() const -{ - const StateVariable* step = GetRootComponent()->GetVariable("step"); - if (step == NULL) { - std::cerr << "root component has no 'step' variable? aborting.\n"; - throw std::exception(); - } - - return step->ToInteger(); -} - - -void GXemul::SetStep(uint64_t step) -{ - StateVariable* stepVariable = GetRootComponent()->GetVariable("step"); - if (stepVariable == NULL) { - std::cerr << "root component has no 'step' variable? aborting.\n"; - throw std::exception(); - } - - stepVariable->SetValue(step); -} - - -UI* GXemul::GetUI() -{ - return m_ui; -} - - -refcount_ptr GXemul::GetRootComponent() -{ - return m_rootComponent; -} - - -const refcount_ptr GXemul::GetRootComponent() const -{ - return m_rootComponent; -} - - -void GXemul::SetRootComponent(refcount_ptr newRootComponent) -{ - if (newRootComponent.IsNULL()) { - std::cerr << "GXemul::SetRootComponent: NULL\n"; - throw std::exception(); - } - - RootComponent* rootComponent = newRootComponent->AsRootComponent(); - if (rootComponent == NULL) { - std::cerr << "GXemul::SetRootComponent: not a RootComponent\n"; - throw std::exception(); - } - - rootComponent->SetOwner(this); - - m_rootComponent = newRootComponent; - - GetUI()->UpdateUI(); -} - - -bool GXemul::Reset() -{ - // 1. Reset all components in the tree. - GetRootComponent()->Reset(); - - // 2. Run "on reset" commands. (These are usually commands to load - // binaries into CPUs.) - vector::const_iterator it = m_onResetCommands.begin(); - for (; it != m_onResetCommands.end(); ++it) { - string cmd = *it; - bool success = false; - - GetCommandInterpreter().RunCommand(cmd, &success); - - if (!GetQuietMode()) - GetUI()->ShowDebugMessage("\n"); - - if (!success) { - GetUI()->ShowDebugMessage("Failing on-reset command:\n" - " " + cmd + "\n"); - return false; - } - } - - return true; -} - - -void GXemul::Interrupt() -{ - switch (GetRunState()) { - case SingleStepping: - case Running: - m_interrupting = true; - break; - default: - m_interrupting = false; - } -} - - -void GXemul::SetRunState(RunState newState) -{ - m_runState = newState; - - GetUI()->UpdateUI(); -} - - -GXemul::RunState GXemul::GetRunState() const -{ - return m_runState; -} - - -string GXemul::GetRunStateAsString() const -{ - switch (m_runState) { - case Paused: - return "Paused"; - case SingleStepping: - return "Single-stepping"; - case Running: - return "Running"; - case Quitting: - return "Quitting"; - } - - return "Unknown RunState"; -} - - -bool GXemul::GetSnapshottingEnabled() const -{ - return m_snapshottingEnabled; -} - - -void GXemul::SetSnapshottingEnabled(bool enabled) -{ - if (enabled) - GetUI()->ShowDebugMessage("(Enabling " - "snapshotting/reverse execution support.)\n"); - - m_snapshottingEnabled = enabled; -} - - -bool GXemul::GetQuietMode() const -{ - return m_quietMode; -} - - -void GXemul::SetQuietMode(bool quietMode) -{ - m_quietMode = quietMode; -} - - -void GXemul::SetNrOfSingleStepsInARow(uint64_t steps) -{ - if (steps < 1) - steps = 1; - - m_nrOfSingleStepsLeft = steps; -} - - -bool GXemul::ModifyStep(int64_t oldStep, int64_t newStep) -{ - if (!GetSnapshottingEnabled()) - return false; - - if (oldStep == newStep) - return true; - - if (newStep < oldStep) { - // Run in reverse, by running forward from the most suitable - // snapshot. - - // TODO: Multiple snapshots! - refcount_ptr newRoot = m_snapshot->Clone(); - SetRootComponent(newRoot); - - // GetStep will now return the step count for the new root. - int64_t nrOfStepsToRunFromSnapshot = newStep - GetStep(); - - RunState oldRunState = GetRunState(); - SetRunState(Running); - - Execute(nrOfStepsToRunFromSnapshot); - - SetRunState(oldRunState); - } else { - // Run forward, by setting a step breakpoint. - GetUI()->ShowDebugMessage("TODO: run forward by setting a step breakpoint!\n"); - return false; - } - - return true; -} - - -void GXemul::TakeSnapshot() -{ - // TODO: Multiple snapshots! - - if (m_snapshot.IsNULL()) { - stringstream ss; - ss << "(snapshot at step " << GetStep() << ")\n"; - GetUI()->ShowDebugMessage(ss.str()); - - m_snapshot = GetRootComponent()->Clone(); - } -} - - -struct ComponentAndFrequency -{ - refcount_ptr component; - double frequency; - StateVariable* step; - - uint64_t nextTimeToExecute; -}; - - -// Gathers a list of components and their frequencies. (Only components that -// have a variable named "frequency" are executable.) -static void GetComponentsAndFrequencies(refcount_ptr component, - vector& componentsAndFrequencies) -{ - const StateVariable* paused = component->GetVariable("paused"); - const StateVariable* freq = component->GetVariable("frequency"); - StateVariable* step = component->GetVariable("step"); - if (freq != NULL && step != NULL && - (paused == NULL || paused->ToInteger() == 0)) { - struct ComponentAndFrequency caf; - - caf.component = component; - caf.frequency = freq->ToDouble(); - caf.step = step; - caf.nextTimeToExecute = 0; - - componentsAndFrequencies.push_back(caf); - } - - Components children = component->GetChildren(); - for (size_t i=0; i componentsAndFrequencies; - GetComponentsAndFrequencies(GetRootComponent(), componentsAndFrequencies); - - if (componentsAndFrequencies.size() == 0) { - GetUI()->ShowDebugMessage("No executable components" - " found in the configuration.\n"); - SetRunState(Paused); - return; - } - - // Take an initial snapshot at step 0, if snapshotting is enabled: - if (m_snapshottingEnabled && GetStep() == 0) - TakeSnapshot(); - - // Find the fastest component: - double fastestFrequency = componentsAndFrequencies[0].frequency; - size_t fastestComponentIndex = 0; - for (size_t i=0; i fastestFrequency) { - fastestFrequency = componentsAndFrequencies[i].frequency; - fastestComponentIndex = i; - } - - bool printEmptyLineBetweenSteps = false; - - switch (GetRunState()) { - - case SingleStepping: - if (m_nrOfSingleStepsLeft == 0) - m_nrOfSingleStepsLeft = 1; - - // Note that setting run state to something else, OR - // decreasing nr of single steps left to 0, will break the loop. - while (!m_interrupting && m_nrOfSingleStepsLeft > 0 && GetRunState() == SingleStepping) { - uint64_t step = GetStep(); - - if (printEmptyLineBetweenSteps) - GetUI()->ShowDebugMessage("\n"); - else - printEmptyLineBetweenSteps = true; - - stringstream ss; - ss << "step " << step << ": "; - - // Indent all debug output with message header "step X: ": - UI::SetIndentationMessageHelper indentationHelper(GetUI(), ss.str()); - - ++ step; - - // Component X, using frequency fX, should have executed - // nstepsX = steps * fX / fastestFrequency nr of steps. - for (size_t k=0; kToInteger(); - - if (stepsExecutedSoFar > nsteps) { - std::cerr << "Internal error: " << - componentsAndFrequencies[k].component->GetVariable("name")->ToString() << - " has executed " << stepsExecutedSoFar << " steps, goal is " << nsteps << ".\n"; - throw std::exception(); - } - - if (stepsExecutedSoFar < nsteps) { - ++ stepsExecutedSoFar; - - const refcount_ptr lightClone = - GetRootComponent()->LightClone(); - - // Execute one step... - int n = componentsAndFrequencies[k].component->Execute(this, 1); - if (n != 1) { - GetUI()->ShowDebugMessage("Single-stepping aborted.\n"); - SetRunState(Paused); - return; - } - - // ... and write back the number of executed steps: - componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar); - - // Now, let's compare the clone of the component tree - // before execution with what we have now. - stringstream changeMessages; - GetRootComponent()->DetectChanges(lightClone, changeMessages); - string msg = changeMessages.str(); - if (msg.length() > 0) - GetUI()->ShowDebugMessage(msg); - } - } - - SetStep(step); - -- m_nrOfSingleStepsLeft; - } - - // Done. Let's pause again. - SetRunState(Paused); - m_nrOfSingleStepsLeft = 0; - break; - - case Running: - { - uint64_t step = GetStep(); - uint64_t startingStep = step; - - // TODO: sloppy vs cycle accuracy. - if (GetRootComponent()->GetVariable("accuracy")->ToString() != "cycle") { - std::cerr << "GXemul::Execute(): TODO: Only " - "root.accuracy=\"cycle\" is currently supported\n"; - SetRunState(Paused); - return; - } - - // The following code is for cycle accurate emulation: - - while (step < startingStep + longestTotalRun) { - if (m_interrupting || GetRunState() != Running) - break; - - int toExecute = -1; - - if (componentsAndFrequencies.size() == 1) { - toExecute = longestTotalRun; - componentsAndFrequencies[0].nextTimeToExecute = step; - } else { - // First, calculate the next time step when each - // component k will execute. - // - // For n = 0,1,2,3, ... - // n * fastestFrequency / componentsAndFrequencies[k].frequency - // are the steps at which the component executes - // (when rounded UP! i.e. executing at step 4.2 means that it - // did not execute at step 4, but will at step 5). - - for (size_t k=0; kToInteger()+1) * q; - componentsAndFrequencies[k].nextTimeToExecute = (uint64_t) ceil(c) - 1; - } - - // std::cerr << "step " << step << " debug:\n"; - for (size_t k=0; kGetVariable("name")->ToString() - // << ": " << componentsAndFrequencies[k].nextTimeToExecute << "\n"; - - int diff = componentsAndFrequencies[k].nextTimeToExecute - - componentsAndFrequencies[fastestComponentIndex].nextTimeToExecute; - if (k != fastestComponentIndex) { - if (toExecute == -1 || diff < toExecute) - toExecute = diff; - } - } - - if (toExecute < 1) - toExecute = 1; - } - - if (step + toExecute > startingStep + longestTotalRun) - toExecute = startingStep + longestTotalRun - step; - - // std::cerr << " toExecute = " << toExecute << "\n"; - - // Run the components. - // If multiple components are to run at the same time (i.e. - // same nextTimeToExecute), toExecute will be exactly 1. - int maxExecuted = 0; - bool abort = false; - for (size_t k=0; kExecute(this, toExecute); - - // ... and write back the number of executed steps: - uint64_t stepsExecutedSoFar = n + - componentsAndFrequencies[k].step->ToInteger(); - componentsAndFrequencies[k].step->SetValue(stepsExecutedSoFar); - - if (k == fastestComponentIndex) - maxExecuted = n; - - if (n != toExecute) { - abort = true; - - if (n > toExecute) { - std::cerr << "Internal error: " << n << - " steps executed, toExecute = " << toExecute << "\n"; - throw std::exception(); - } - - stringstream ss; - ss << "only " << n << " steps of " << toExecute << " executed."; - GetUI()->ShowDebugMessage(componentsAndFrequencies[k].component, ss.str()); - } - } - - if (abort) { - GetUI()->ShowDebugMessage("Continuous execution aborted.\n"); - SetRunState(Paused); - } - - if (maxExecuted == 0 && GetRunState() == Running) { - std::cerr << "maxExecuted=0. internal error\n"; - throw std::exception(); - } - - step += maxExecuted; - SetStep(step); - } - - // Output nr of steps (and speed) every second: - struct timeval tvend; - gettimeofday(&tvend, NULL); - - double secondsSinceLastOutput = - ((double)tvend.tv_sec + tvend.tv_usec / 1000000.0) - - ((double)m_lastOutputTime.tv_sec + m_lastOutputTime.tv_usec / 1000000.0); - - if (secondsSinceLastOutput > 1.0 && (step - m_lastOutputStep) > 10000) { - m_lastOutputTime = tvend; - - int64_t stepsPerSecond = (int64_t) - ( (double)(step - m_lastOutputStep) / secondsSinceLastOutput ); - m_lastOutputStep = step; - - stringstream ss; - ss << step << " steps"; - if (stepsPerSecond > 0) - ss << " (" << stepsPerSecond << " steps/second)"; - - GetUI()->ShowDebugMessage(ss.str()); - } - } - break; - - default: - std::cerr << "GXemul::Execute() called without being in a" - " running state. Internal error?\n"; - throw std::exception(); - } - - if (m_interrupting) { - m_interrupting = false; - SetRunState(Paused); - } -} - - -/*****************************************************************************/ - -#ifdef WITHUNITTESTS - -static void Test_Construction() -{ - GXemul gxemul; -} - -UNITTESTS(GXemul) -{ - UNITTEST(Test_Construction); - - // Note: Most execution tests are in DummyComponent.cc, because they - // test component behavior. But they also test GXemul::Execute etc. -} - - -#endif - diff -Nru gxemul-0.6.2/src/main/Makefile.skel gxemul-0.7.0+dfsg/src/main/Makefile.skel --- gxemul-0.6.2/src/main/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/Makefile.skel 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# -# Makefile for GXemul src/main -# - -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) - -OBJS=Checksum.o Command.o CommandInterpreter.o Component.o ComponentFactory.o \ - EscapedString.o FileLoader.o GXemul.o StateVariable.o \ - StringHelper.o SymbolRegistry.o UnitTest.o debug_new.o - -all: $(OBJS) do_commands do_fileloaders - -$(OBJS): Makefile - -do_commands: - cd commands; $(MAKE) - -do_fileloaders: - cd fileloaders; $(MAKE) - -clean: - cd commands; $(MAKE) clean - cd fileloaders; $(MAKE) clean - rm -f $(OBJS) *core - -clean_all: clean - cd commands; $(MAKE) clean_all - cd fileloaders; $(MAKE) clean_all - rm -f Makefile - - diff -Nru gxemul-0.6.2/src/main/StateVariable.cc gxemul-0.7.0+dfsg/src/main/StateVariable.cc --- gxemul-0.6.2/src/main/StateVariable.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/StateVariable.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,968 +0,0 @@ -/* - * Copyright (C) 2007-2010 Anders Gavare. 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -#include "EscapedString.h" -#include "StateVariable.h" -#include "StringHelper.h" - - -StateVariable::StateVariable(const string& name, string* ptrToString) - : m_name(name) - , m_type(String) -{ - m_value.pstr = ptrToString; -} - - -StateVariable::StateVariable(const string& name, bool* ptrToVar) - : m_name(name) - , m_type(Bool) -{ - m_value.pbool = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, double* ptrToVar) - : m_name(name) - , m_type(Double) -{ - m_value.pdouble = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, uint8_t* ptrToVar) - : m_name(name) - , m_type(UInt8) -{ - m_value.puint8 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, uint16_t* ptrToVar) - : m_name(name) - , m_type(UInt16) -{ - m_value.puint16 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, uint32_t* ptrToVar) - : m_name(name) - , m_type(UInt32) -{ - m_value.puint32 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, uint64_t* ptrToVar) - : m_name(name) - , m_type(UInt64) -{ - m_value.puint64 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, int8_t* ptrToVar) - : m_name(name) - , m_type(SInt8) -{ - m_value.psint8 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, int16_t* ptrToVar) - : m_name(name) - , m_type(SInt16) -{ - m_value.psint16 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, int32_t* ptrToVar) - : m_name(name) - , m_type(SInt32) -{ - m_value.psint32 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, int64_t* ptrToVar) - : m_name(name) - , m_type(SInt64) -{ - m_value.psint64 = ptrToVar; -} - - -StateVariable::StateVariable(const string& name, CustomStateVariableHandler* ptrToHandler) - : m_name(name) - , m_type(Custom) -{ - m_value.phandler = ptrToHandler; -} - - -enum StateVariable::Type StateVariable::GetType() const -{ - return m_type; -} - - -const string& StateVariable::GetName() const -{ - return m_name; -} - - -string StateVariable::GetTypeString() const -{ - switch (m_type) { - case String: - return "string"; - case Bool: - return "bool"; - case Double: - return "double"; - case UInt8: - return "uint8"; - case UInt16: - return "uint16"; - case UInt32: - return "uint32"; - case UInt64: - return "uint64"; - case SInt8: - return "sint8"; - case SInt16: - return "sint16"; - case SInt32: - return "sint32"; - case SInt64: - return "sint64"; - case Custom: - return "custom"; - default: - return "unknown"; - } -} - - -bool StateVariable::CopyValueFrom(const StateVariable& otherVariable) -{ - if (m_type != otherVariable.m_type) - return false; - - switch (m_type) { - case String: - *m_value.pstr = *otherVariable.m_value.pstr; - break; - case Bool: - *m_value.pbool = *otherVariable.m_value.pbool; - break; - case Double: - *m_value.pdouble = *otherVariable.m_value.pdouble; - break; - case UInt8: - *m_value.puint8 = *otherVariable.m_value.puint8; - break; - case UInt16: - *m_value.puint16 = *otherVariable.m_value.puint16; - break; - case UInt32: - *m_value.puint32 = *otherVariable.m_value.puint32; - break; - case UInt64: - *m_value.puint64 = *otherVariable.m_value.puint64; - break; - case SInt8: - *m_value.psint8 = *otherVariable.m_value.psint8; - break; - case SInt16: - *m_value.psint16 = *otherVariable.m_value.psint16; - break; - case SInt32: - *m_value.psint32 = *otherVariable.m_value.psint32; - break; - case SInt64: - *m_value.psint64 = *otherVariable.m_value.psint64; - break; - case Custom: - m_value.phandler->CopyValueFrom(otherVariable.m_value.phandler); - break; - default: - // Unknown type? - assert(false); - return false; - } - - return true; -} - - -string StateVariable::ToString() const -{ - stringstream sstr; - - switch (m_type) { - case String: - return m_value.pstr == NULL? "" : *m_value.pstr; - case Bool: - sstr << (*m_value.pbool? "true" : "false"); - return sstr.str(); - case Double: - sstr << *m_value.pdouble; - return sstr.str(); - case UInt8: - sstr << (int) *m_value.puint8; - return sstr.str(); - case UInt16: - sstr.flags(std::ios::hex | std::ios::showbase); - sstr << *m_value.puint16; - return sstr.str(); - case UInt32: - sstr.flags(std::ios::hex | std::ios::showbase); - sstr << *m_value.puint32; - return sstr.str(); - case UInt64: - sstr.flags(std::ios::hex | std::ios::showbase); - sstr << *m_value.puint64; - return sstr.str(); - case SInt8: - sstr << (int) *m_value.psint8; - return sstr.str(); - case SInt16: - sstr << *m_value.psint16; - return sstr.str(); - case SInt32: - sstr << *m_value.psint32; - return sstr.str(); - case SInt64: - sstr << *m_value.psint64; - return sstr.str(); - case Custom: - return "(custom)"; - } - - // Unimplemented type? - assert(false); - - return ""; -} - - -uint64_t StateVariable::ToInteger() const -{ - switch (m_type) { - case String: - { - uint64_t tmp; - stringstream ss; - ss << *m_value.pstr; - ss >> tmp; - return tmp; - } - case Bool: - return (*m_value.pbool)? 1 : 0; - case Double: - return (uint64_t) *m_value.pdouble; - case UInt8: - return *m_value.puint8; - case UInt16: - return *m_value.puint16; - case UInt32: - return *m_value.puint32; - case UInt64: - return *m_value.puint64; - case SInt8: - return *m_value.psint8; - case SInt16: - return *m_value.psint16; - case SInt32: - return *m_value.psint32; - case SInt64: - return *m_value.psint64; - case Custom: - return 0; - } - - // Unimplemented type. Let's abort. - std::cerr << "StateVariable::ToDouble(): Unimplemented type.\n"; - throw std::exception(); -} - - -double StateVariable::ToDouble() const -{ - switch (m_type) { - case String: - { - double tmp; - stringstream ss; - ss << *m_value.pstr; - ss >> tmp; - return tmp; - } - case Bool: - return (*m_value.pbool)? 1.0 : 0.0; - case Double: - return *m_value.pdouble; - case UInt8: - return *m_value.puint8; - case UInt16: - return *m_value.puint16; - case UInt32: - return *m_value.puint32; - case UInt64: - return *m_value.puint64; - case SInt8: - return *m_value.psint8; - case SInt16: - return *m_value.psint16; - case SInt32: - return *m_value.psint32; - case SInt64: - return *m_value.psint64; - case Custom: - return 0.0; - } - - // Unimplemented type. Let's abort. - std::cerr << "StateVariable::ToDouble(): Unimplemented type.\n"; - throw std::exception(); -} - - -void StateVariable::SerializeValue(ostream& ss) const -{ - switch (m_type) { - - case String: - { - EscapedString escaped(ToString()); - ss << escaped.Generate(); - } - break; - - case Custom: - m_value.phandler->Serialize(ss); - break; - - default: - ss << ToString(); - } -} - - -void StateVariable::Serialize(ostream& ss, SerializationContext& context) const -{ - ss << context.Tabs() << GetTypeString() << " " << m_name + " "; - SerializeValue(ss); - ss << "\n"; -} - - -string StateVariable::EvaluateExpression(const string& expression, - bool& success) const -{ - success = false; - - string result = expression; - - // Remove leading and trailing spaces: - while (result.size() > 0 && result[0] == ' ') - result.erase((size_t) 0); - while (result.size() > 0 && result[result.size() - 1] == ' ') - result.erase(result.size()-1); - -// TODO -success = true; -return result; - - return ""; -} - - -bool StateVariable::SetValue(const string& expression) -{ - // Nothing to assign to? - if (m_value.pstr == NULL) - return false; - - // Reduce the expression to a single value. - bool success = false; - string value = EvaluateExpression(expression, success); - if (!success) - return false; - - switch (m_type) { - - case String: - { - success = false; - string newStr = EscapedString(value).Decode(success); - if (success) - *m_value.pstr = newStr; - else - return false; - } - return true; - - case Bool: - { - if (value == "true") - *m_value.pbool = true; - else if (value == "false") - *m_value.pbool = false; - else - return false; - } - return true; - - case Double: - { - double doubleTmp; - stringstream sstr; - sstr << value; - sstr >> doubleTmp; - if (isnan(doubleTmp) || isinf(doubleTmp)) - return false; - *m_value.pdouble = doubleTmp; - } - return true; - - case UInt8: - { - bool error = true; - uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - uint8_t tmp = tmp64; - if (tmp == tmp64 && !error) - *m_value.puint8 = tmp; - else - return false; - } - return true; - - case UInt16: - { - bool error = true; - uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - uint16_t tmp = tmp64; - if (tmp == tmp64 && !error) - *m_value.puint16 = tmp; - else - return false; - } - return true; - - case UInt32: - { - bool error = true; - uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - uint32_t tmp = tmp64; - if (tmp == tmp64 && !error) - *m_value.puint32 = tmp; - else - return false; - } - return true; - - case UInt64: - { - bool error = true; - uint64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - if (!error) - *m_value.puint64 = tmp64; - else - return false; - } - return true; - - case SInt8: - { - bool error = true; - int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - int8_t tmp = tmp64; - if (tmp == tmp64 && !error) - *m_value.psint8 = tmp; - else - return false; - } - return true; - - case SInt16: - { - bool error = true; - int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - int16_t tmp = tmp64; - if (tmp == tmp64 && !error) - *m_value.psint16 = tmp; - else - return false; - } - return true; - - case SInt32: - { - bool error = true; - int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - int32_t tmp = tmp64; - if (tmp == tmp64 && !error) - *m_value.psint32 = tmp; - else - return false; - } - return true; - - case SInt64: - { - bool error = true; - int64_t tmp64 = StringHelper::ParseNumber(value.c_str(), error); - if (!error) - *m_value.psint64 = tmp64; - else - return false; - } - return true; - - case Custom: - return m_value.phandler->Deserialize(value); - - default: - // Unimplemented type. Let's abort. - std::cerr << "StateVariable::SetValue: Unimplemented type.\n"; - throw std::exception(); - } -} - - -bool StateVariable::SetValue(uint64_t value) -{ - // Nothing to assign to? - if (m_value.pstr == NULL) - return false; - - switch (m_type) { - - case String: - { - stringstream ss; - ss << value; - *m_value.pstr = ss.str(); - } - return true; - - case Bool: - *m_value.pbool = value != 0; - return true; - - case Double: - *m_value.pdouble = value; - return true; - - case UInt8: - *m_value.puint8 = value; - return true; - - case UInt16: - *m_value.puint16 = value; - return true; - - case UInt32: - *m_value.puint32 = value; - return true; - - case UInt64: - *m_value.puint64 = value; - return true; - - case SInt8: - *m_value.psint8 = value; - return true; - - case SInt16: - *m_value.psint16 = value; - return true; - - case SInt32: - *m_value.psint32 = value; - return true; - - case SInt64: - *m_value.psint64 = value; - return true; - - case Custom: - return false; - - default: - // Unimplemented type. Let's abort. - std::cerr << "StateVariable::SetValue: Unimplemented type.\n"; - throw std::exception(); - } -} - - -/*****************************************************************************/ - - -#ifdef WITHUNITTESTS - -static void Test_StateVariable_String_Construct() -{ - string myString = "hi"; - - StateVariable var("hello", &myString); - - UnitTest::Assert("name should be hello", - var.GetName(), "hello"); - UnitTest::Assert("type should be String", - var.GetType() == StateVariable::String); - UnitTest::Assert("value should be hi", - var.ToString(), "hi"); -} - -static void Test_StateVariable_String_SetValue() -{ - string myString = "hi"; - - StateVariable var("hello", &myString); - - UnitTest::Assert("setting string value without quotes should not work", - var.SetValue("value2") == false); - UnitTest::Assert("setting string value with quotes should work", - var.SetValue("\"value2\"") == true); - - UnitTest::Assert("type should still be String", - var.GetType() == StateVariable::String); - UnitTest::Assert("value should now be value2", - var.ToString(), "value2"); - UnitTest::Assert("myString should have been updated", - myString, "value2"); -} - -static void Test_StateVariable_String_CopyValueFrom() -{ - string myString1 = "hi"; - string myString2 = "something"; - - StateVariable var1("hello", &myString1); - StateVariable var2("world", &myString2); - - UnitTest::Assert("value should initially be hi", - var1.ToString(), "hi"); - - var1.CopyValueFrom(var2); - - UnitTest::Assert("name should still be hello", - var1.GetName(), "hello"); - UnitTest::Assert("type should still be String", - var1.GetType() == StateVariable::String); - UnitTest::Assert("value should be changed to something", - var1.ToString(), "something"); - UnitTest::Assert("myString1 should have been updated", - myString1, "something"); -} - -static void Test_StateVariable_String_Serialize() -{ - string hi = "value world"; - StateVariable var("hello", &hi); - - SerializationContext dummyContext; - stringstream ss; - - var.Serialize(ss, dummyContext); - UnitTest::Assert("variable serialization mismatch?", - ss.str(), "string hello \"value world\"\n"); -} - -static void Test_StateVariable_String_Serialize_WithEscapes() -{ - string s = "a\\b\tc\nd\re\bf\"g'h"; - StateVariable var("hello", &s); - - SerializationContext dummyContext; - stringstream ss; - - var.Serialize(ss, dummyContext); - UnitTest::Assert("variable serialization mismatch?", - ss.str(), - "string hello " + EscapedString(s).Generate() + "\n"); -} - -static void Test_StateVariable_Bool_Construct() -{ - bool myBool = true; - - StateVariable var("hello", &myBool); - - UnitTest::Assert("name should be hello", - var.GetName(), "hello"); - UnitTest::Assert("type should be Bool", - var.GetType() == StateVariable::Bool); - UnitTest::Assert("value should be true", - var.ToString(), "true"); -} - -static void Test_StateVariable_Bool_SetValue() -{ - bool myBool = true; - - StateVariable var("hello", &myBool); - - UnitTest::Assert("changing to false should be possible", - var.SetValue("false") == true); - - UnitTest::Assert("type should still be Bool", - var.GetType() == StateVariable::Bool); - UnitTest::Assert("value should now be changed", - var.ToString(), "false"); - UnitTest::Assert("myBool should have been updated", - myBool == false); - - UnitTest::Assert("changing to true should be possible", - var.SetValue("true") == true); - - UnitTest::Assert("value should now be changed again", - var.ToString(), "true"); - UnitTest::Assert("myBool should have been updated again", - myBool == true); - - UnitTest::Assert("changing to non-bool value should not be possible", - var.SetValue("hello") == false); - - UnitTest::Assert("value should not be changed", - var.ToString(), "true"); -} - -static void Test_StateVariable_Bool_CopyValueFrom() -{ - bool myBool1 = false; - bool myBool2 = true; - - StateVariable var1("hello", &myBool1); - StateVariable var2("world", &myBool2); - - UnitTest::Assert("copying from bool to bool should be possible", - var1.CopyValueFrom(var2) == true); - - UnitTest::Assert("name should still be hello", - var1.GetName(), "hello"); - UnitTest::Assert("type should still be Bool", - var1.GetType() == StateVariable::Bool); - UnitTest::Assert("value should be changed to true", - var1.ToString(), "true"); - UnitTest::Assert("myBool1 should have been updated", - myBool1 == true); - - string myString = "hm"; - StateVariable var3("test", &myString); - - UnitTest::Assert("copying from string to bool should not be possible", - var1.CopyValueFrom(var3) == false); -} - -static void Test_StateVariable_Bool_Serialize() -{ - bool myBool = true; - StateVariable var("hello", &myBool); - - SerializationContext dummyContext; - stringstream ss; - - var.Serialize(ss, dummyContext); - UnitTest::Assert("variable serialization mismatch (1)", - ss.str(), "bool hello true\n"); - - myBool = false; - stringstream ss2; - var.Serialize(ss2, dummyContext); - - UnitTest::Assert("variable serialization mismatch (2)", - ss2.str(), "bool hello false\n"); -} - -static void Test_StateVariable_Numeric_Construct() -{ - double varDouble = -12.345; - uint8_t varUInt8 = 223; - uint16_t varUInt16 = 55000; - uint32_t varUInt32 = 3000000001UL; - uint64_t varUInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; - int8_t varSInt8 = -120; - int16_t varSInt16 = -22000; - int32_t varSInt32 = -1000000001; - int64_t varSInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; - - StateVariable vdouble("vdouble", &varDouble); - StateVariable vuint8 ("vuint8", &varUInt8); - StateVariable vuint16("vuint16", &varUInt16); - StateVariable vuint32("vuint32", &varUInt32); - StateVariable vuint64("vuint64", &varUInt64); - StateVariable vsint8 ("vsint8", &varSInt8); - StateVariable vsint16("vsint16", &varSInt16); - StateVariable vsint32("vsint32", &varSInt32); - StateVariable vsint64("vsint64", &varSInt64); - - // Types - UnitTest::Assert("Double", vdouble.GetType() == StateVariable::Double); - UnitTest::Assert("UInt8", vuint8.GetType() == StateVariable::UInt8); - UnitTest::Assert("UInt16", vuint16.GetType() == StateVariable::UInt16); - UnitTest::Assert("UInt32", vuint32.GetType() == StateVariable::UInt32); - UnitTest::Assert("UInt64", vuint64.GetType() == StateVariable::UInt64); - UnitTest::Assert("SInt8", vsint8.GetType() == StateVariable::SInt8); - UnitTest::Assert("SInt16", vsint16.GetType() == StateVariable::SInt16); - UnitTest::Assert("SInt32", vsint32.GetType() == StateVariable::SInt32); - UnitTest::Assert("SInt64", vsint64.GetType() == StateVariable::SInt64); - - // Values - UnitTest::Assert("value Double", vdouble.ToString(), "-12.345"); - UnitTest::Assert("value UInt8", vuint8.ToString(), "223"); - UnitTest::Assert("value UInt16", vuint16.ToString(), "0xd6d8"); - UnitTest::Assert("value UInt32", vuint32.ToString(), "0xb2d05e01"); - UnitTest::Assert("value UInt64", vuint64.ToString(), - "0xfedc010203040506"); - UnitTest::Assert("value SInt8", vsint8.ToString(), "-120"); - UnitTest::Assert("value SInt16", vsint16.ToString(), "-22000"); - UnitTest::Assert("value SInt32", vsint32.ToString(), "-1000000001"); - UnitTest::Assert("value SInt64", vsint64.ToString(), - "-82189585047354106"); -} - -static void Test_StateVariable_Numeric_SetValue() -{ - double varDouble = -12.345; - uint8_t varUInt8 = 223; - uint16_t varUInt16 = 55000; - uint32_t varUInt32 = 3000000001UL; - uint64_t varUInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; - int8_t varSInt8 = -120; - int16_t varSInt16 = -22000; - int32_t varSInt32 = -1000000001; - int64_t varSInt64 = ((uint64_t) 0xfedc0102 << 32) | 0x03040506; - - StateVariable vdouble("vdouble", &varDouble); - StateVariable vuint8 ("vuint8", &varUInt8); - StateVariable vuint16("vuint16", &varUInt16); - StateVariable vuint32("vuint32", &varUInt32); - StateVariable vuint64("vuint64", &varUInt64); - StateVariable vsint8 ("vsint8", &varSInt8); - StateVariable vsint16("vsint16", &varSInt16); - StateVariable vsint32("vsint32", &varSInt32); - StateVariable vsint64("vsint64", &varSInt64); - - UnitTest::Assert("changing to 'hello' should not be possible", - vuint8.SetValue("hello") == false); - - // Double - UnitTest::Assert("changing to 100 should be possible", - vdouble.SetValue("100") == true); - UnitTest::Assert("varDouble should have been updated", - varDouble == 100); - UnitTest::Assert("changing to -210.42 should be possible", - vdouble.SetValue("-210.42") == true); - UnitTest::Assert("varDouble should not have been updated", - varDouble == -210.42); - UnitTest::Assert("changing to 1e-100 should be possible (2)", - vdouble.SetValue("1e-100") == true); - UnitTest::Assert("varDouble should have been updated (2)", - varDouble == 1e-100); - - // UInt8 - UnitTest::Assert("changing to 100 should be possible", - vuint8.SetValue("100") == true); - UnitTest::Assert("varUInt8 should have been updated", - varUInt8, 100); - UnitTest::Assert("changing to 0x2f should be possible", - vuint8.SetValue("0x2f") == true); - UnitTest::Assert("varUInt8 should have been updated to 0x2f", - varUInt8, 0x2f); - UnitTest::Assert("changing to 300 should not be possible", - vuint8.SetValue("300") == false); - UnitTest::Assert("varUInt8 should not have been updated", - varUInt8, 0x2f); - UnitTest::Assert("changing to -110 should not be possible", - vuint8.SetValue("-110") == false); - UnitTest::Assert("varUInt8 should not have been updated", - varUInt8, 0x2f); - - // SInt8 - UnitTest::Assert("changing to 100 should be possible", - vsint8.SetValue("100") == true); - UnitTest::Assert("varSInt8 should have been updated", - varSInt8, 100); - UnitTest::Assert("changing to 200 should not be possible", - vsint8.SetValue("200") == false); - UnitTest::Assert("varSInt8 should not have been updated", - varSInt8, 100); - UnitTest::Assert("changing to -210 should not be possible", - vsint8.SetValue("-210") == false); - UnitTest::Assert("varSInt8 should not have been updated", - varSInt8, 100); - UnitTest::Assert("changing to -110 should be possible", - vsint8.SetValue("-110") == true); - UnitTest::Assert("varSInt8 should have been updated", - varSInt8, (uint64_t) -110); - UnitTest::Assert("changing to -0x1a should be possible", - vsint8.SetValue("-0x1a") == true); - UnitTest::Assert("varSInt8 should have been updated", - varSInt8, (uint64_t) -0x1a); - - // Tests for other numeric types: TODO -} - -UNITTESTS(StateVariable) -{ - // String tests - UNITTEST(Test_StateVariable_String_Construct); - UNITTEST(Test_StateVariable_String_SetValue); - UNITTEST(Test_StateVariable_String_CopyValueFrom); - UNITTEST(Test_StateVariable_String_Serialize); - UNITTEST(Test_StateVariable_String_Serialize_WithEscapes); - - // Bool tests - UNITTEST(Test_StateVariable_Bool_Construct); - UNITTEST(Test_StateVariable_Bool_SetValue); - UNITTEST(Test_StateVariable_Bool_CopyValueFrom); - UNITTEST(Test_StateVariable_Bool_Serialize); - - // Numeric tests - UNITTEST(Test_StateVariable_Numeric_Construct); - UNITTEST(Test_StateVariable_Numeric_SetValue); - //UNITTEST(Test_StateVariable_Numeric_CopyValueFrom); - //UNITTEST(Test_StateVariable_Numeric_Serialize); - - // TODO: ToInteger tests. - - // TODO: Custom tests. -} - -#endif - diff -Nru gxemul-0.6.2/src/main/StringHelper.cc gxemul-0.7.0+dfsg/src/main/StringHelper.cc --- gxemul-0.6.2/src/main/StringHelper.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/StringHelper.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2010 Anders Gavare. 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. The name of the author 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 "StringHelper.h" - - -// This is basically strtoull(), but it needs to be explicitly implemented -// since some systems lack it. (Also, compiling with GNU C++ in ANSI mode -// does not work with strtoull.) -uint64_t StringHelper::ParseNumber(const char* str, bool& error) -{ - bool baseSet = false; - int base = 10; - uint64_t result = 0; - bool negative = false; - - error = false; - - if (str == NULL) - return 0; - - while (*str == ' ') - ++str; - - if (*str == '-') { - negative = true; - ++str; - } - - while ((*str == 'x' || *str == 'X') || (*str >= '0' && *str <= '9') - || (*str >= 'a' && *str <= 'f') || (*str >= 'A' && *str <= 'F')) { - char c = *str; - - if (c == 'x' || c == 'X') { - // Multiple base selections are not allowed. - if (baseSet) - break; - - // Only 0 prefix before base selection is allowed, - // no other values. - if (result != 0) - break; - - base = 16; - baseSet = true; - } else { - if (base == 10 && (c < '0' || c > '9')) - break; - - int n = c - '0'; - if (c >= 'a' && c <= 'f') - n = *str - 'a' + 10; - if (c >= 'A' && c <= 'F') - n = *str - 'A' + 10; - - if (base == 16 && (n < 0 || n > 15)) - break; - - result = result * base + n; - } - - ++str; - } - - if (*str) - error = true; - - if (negative) - return -result; - else - return result; -} - - -vector StringHelper::SplitStringIntoVector(const string &str, const char splitter) -{ - // This is slow and hackish, but works. - vector strings; - string word; - bool lastWasSplitter = false; - - for (size_t i=0, n=str.length(); i v = StringHelper::SplitStringIntoVector("A:B:C", ':'); - - UnitTest::Assert("Wrong number of strings?", v.size(), 3); - UnitTest::Assert("Wrong string contents?", v[0], "A"); - UnitTest::Assert("Wrong string contents?", v[1], "B"); - UnitTest::Assert("Wrong string contents?", v[2], "C"); -} - -static void Test_StringHelper_SplitStringIntoVector_EmptyInput() -{ - vector v = StringHelper::SplitStringIntoVector("", ':'); - - UnitTest::Assert("Wrong number of strings?", v.size(), 0); -} - -static void Test_StringHelper_SplitStringIntoVector_Simple2() -{ - vector v = StringHelper::SplitStringIntoVector("A:B:C", 'B'); - - UnitTest::Assert("Wrong number of strings?", v.size(), 2); - UnitTest::Assert("Wrong string contents?", v[0], "A:"); - UnitTest::Assert("Wrong string contents?", v[1], ":C"); -} - -static void Test_StringHelper_SplitStringIntoVector_WithZeroLengthParts() -{ - vector v = StringHelper::SplitStringIntoVector("A::B:::C", ':'); - - UnitTest::Assert("Wrong number of strings?", v.size(), 6); - UnitTest::Assert("Wrong string contents?", v[0], "A"); - UnitTest::Assert("Wrong string contents?", v[1], ""); - UnitTest::Assert("Wrong string contents?", v[2], "B"); - UnitTest::Assert("Wrong string contents?", v[3], ""); - UnitTest::Assert("Wrong string contents?", v[4], ""); - UnitTest::Assert("Wrong string contents?", v[5], "C"); -} - -static void Test_StringHelper_SplitStringIntoVector_WithTrailingZeroLengthParts() -{ - vector v = StringHelper::SplitStringIntoVector("A::", ':'); - - UnitTest::Assert("Wrong number of strings?", v.size(), 3); - UnitTest::Assert("Wrong string contents?", v[0], "A"); - UnitTest::Assert("Wrong string contents?", v[1], ""); - UnitTest::Assert("Wrong string contents?", v[2], ""); -} - -static void Test_StringHelper_SplitStringIntoVector_WithHeadingZeroLengthParts() -{ - vector v = StringHelper::SplitStringIntoVector("A::", 'A'); - - UnitTest::Assert("Wrong number of strings?", v.size(), 2); - UnitTest::Assert("Wrong string contents?", v[0], ""); - UnitTest::Assert("Wrong string contents?", v[1], "::"); -} - -UNITTESTS(StringHelper) -{ - UNITTEST(Test_StringHelper_ParseNumber_Simple); - UNITTEST(Test_StringHelper_ParseNumber_SimpleError); - UNITTEST(Test_StringHelper_ParseNumber_Negative); - UNITTEST(Test_StringHelper_ParseNumber_LeadingSpaces); - UNITTEST(Test_StringHelper_ParseNumber_LeadingSpacesAndNegative); - UNITTEST(Test_StringHelper_ParseNumber_LeadingSpacesAndErrorNegative); - UNITTEST(Test_StringHelper_ParseNumber_SimpleHexLowerCase); - UNITTEST(Test_StringHelper_ParseNumber_SimpleHexUpperCase); - UNITTEST(Test_StringHelper_ParseNumber_HexErrorDoubleX); - UNITTEST(Test_StringHelper_ParseNumber_HexErrorNonZeroPrefix); - UNITTEST(Test_StringHelper_ParseNumber_NumberFollowedByErrorValidHexChar); - UNITTEST(Test_StringHelper_ParseNumber_NumberFollowedByError); - - UNITTEST(Test_StringHelper_SplitStringIntoVector_Simple); - UNITTEST(Test_StringHelper_SplitStringIntoVector_EmptyInput); - UNITTEST(Test_StringHelper_SplitStringIntoVector_Simple2); - UNITTEST(Test_StringHelper_SplitStringIntoVector_WithZeroLengthParts); - UNITTEST(Test_StringHelper_SplitStringIntoVector_WithTrailingZeroLengthParts); - UNITTEST(Test_StringHelper_SplitStringIntoVector_WithHeadingZeroLengthParts); -} - -#endif - diff -Nru gxemul-0.6.2/src/main/SymbolRegistry.cc gxemul-0.7.0+dfsg/src/main/SymbolRegistry.cc --- gxemul-0.6.2/src/main/SymbolRegistry.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/SymbolRegistry.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2009-2010 Anders Gavare. 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. The name of the author 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 "SymbolRegistry.h" - - -SymbolRegistry::SymbolRegistry() -{ -} - - -void SymbolRegistry::Clear() -{ - m_map.clear(); -} - - -void SymbolRegistry::AddSymbol(const string& symbol, uint64_t vaddr) -{ - m_map[vaddr] = symbol; -} - - -string SymbolRegistry::LookupAddress(uint64_t vaddr, bool allowOffset) const -{ - // Must be an exact match? - if (!allowOffset) { - SymbolMap::const_iterator a = m_map.find(vaddr); - return a == m_map.end()? "" : a->second; - } - - // Try to find the symbol given the address, or at least some - // symbol close to it: - SymbolMap::const_iterator a = m_map.lower_bound(vaddr); - if (a == m_map.end()) { - if (m_map.empty()) - return ""; - - a = m_map.end(); - } - - // Exact match? Then just return the symbol. - if (a != m_map.end() && vaddr == a->first) - return a->second; - - if (a == m_map.begin()) - return ""; - - // Return the symbol _before_ the address, plus an offset. - --a; - - stringstream ss; - ss.flags(std::ios::hex); - ss << a->second << "+0x" << (vaddr - a->first); - return ss.str(); -} - - -/*****************************************************************************/ - - -#ifdef WITHUNITTESTS - -static void Test_SymbolRegistry_Basic() -{ - SymbolRegistry registry; - - registry.AddSymbol("symA", 0x1000); - registry.AddSymbol("symB", 0x1020); - registry.AddSymbol("symC", 0x1060); - - UnitTest::Assert("lookup failed 1?", - registry.LookupAddress(0x1020, true), "symB"); - - UnitTest::Assert("lookup failed 2?", - registry.LookupAddress(0x1020, false), "symB"); - - registry.Clear(); - - UnitTest::Assert("clear failed?", - registry.LookupAddress(0x1020, true), ""); -} - -static void Test_SymbolRegistry_BeforeFirst() -{ - SymbolRegistry registry; - - registry.AddSymbol("symA", 0x1000); - registry.AddSymbol("symB", 0x1020); - - UnitTest::Assert("lookup should have failed 1", - registry.LookupAddress(0xffc, true), ""); - - UnitTest::Assert("lookup should have failed 2", - registry.LookupAddress(0xffc, false), ""); -} - -static void Test_SymbolRegistry_WithOffset() -{ - SymbolRegistry registry; - - registry.AddSymbol("symA", 0x1000); - registry.AddSymbol("symB", 0x1020); - - UnitTest::Assert("lookup failed?", - registry.LookupAddress(0x1006, true), "symA+0x6"); - - UnitTest::Assert("lookup should have failed", - registry.LookupAddress(0x1006, false), ""); -} - -static void Test_SymbolRegistry_AfterLast() -{ - SymbolRegistry registry; - - registry.AddSymbol("symA", 0x1000); - registry.AddSymbol("symB", 0x1020); - - UnitTest::Assert("lookup failed?", - registry.LookupAddress(0x1090, true), "symB+0x70"); - - UnitTest::Assert("lookup should have failed", - registry.LookupAddress(0x1090, false), ""); -} - -UNITTESTS(SymbolRegistry) -{ - UNITTEST(Test_SymbolRegistry_Basic); - UNITTEST(Test_SymbolRegistry_BeforeFirst); - UNITTEST(Test_SymbolRegistry_WithOffset); - UNITTEST(Test_SymbolRegistry_AfterLast); -} - -#endif diff -Nru gxemul-0.6.2/src/main/UnitTest.cc gxemul-0.7.0+dfsg/src/main/UnitTest.cc --- gxemul-0.6.2/src/main/UnitTest.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/main/UnitTest.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2007-2010 Anders Gavare. 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#include "misc.h" -#include "UnitTest.h" - -// The list of classes to test is detected by the configure script, and -// placed in unittest.h, but the classes corresponding .h files also need -// to be included. This is done by unittest_h.h (also generated by the -// configure script). -#include "../../unittest_h.h" - - -void UnitTest::Assert(const string& strFailMessage, bool condition) -{ - if (!condition) - Fail(strFailMessage); -} - - -void UnitTest::Assert(const string& strFailMessage, - uint64_t actualValue, uint64_t expectedValue) -{ - if (actualValue != expectedValue) { - stringstream ss; - ss.flags(std::ios::hex | std::ios::showbase); - ss << strFailMessage << - "\n\tExpected: " << expectedValue << - "\n\tbut was: " << actualValue; - Fail(ss.str()); - } -} - - -void UnitTest::Assert(const string& strFailMessage, - const string& actualValue, const string& expectedValue) -{ - if (actualValue != expectedValue) { - size_t pos; - for (pos = 0; pos < actualValue.length() && pos < expectedValue.length(); pos++) - if (actualValue[pos] != expectedValue[pos]) - break; - - stringstream mismatchPosition; - mismatchPosition << "\n\tMismatch at position " << pos; - - Fail(strFailMessage + mismatchPosition.str() + - "\n\tExpected: \"" + expectedValue + "\"" + - "\n\tbut was: \"" + actualValue + "\""); - } -} - - -void UnitTest::Fail(const string& strMessage) -{ - throw UnitTestFailedException(strMessage); -} - - -#ifndef WITHUNITTESTS - - -int UnitTest::RunTests() -{ - std::cerr << "Skipping unit tests, because WITHUNITTESTS " - "was not defined.\n"; - - return 0; -} - - -#else // WITHUNITTESTS - - -int UnitTest::RunTests() -{ - int nSucceeded = 0, nFailed = 0; - -#include "../../unittest.h" - - if (nFailed == 0) - std::cerr << nSucceeded << " (all) tests passed.\n"; - else - std::cerr << "\n" << nFailed << " TESTS FAILED!\n"; - - // Returns 0 if there were no errors. - return nFailed > 0; -} - - -#endif // WITHUNITTESTS diff -Nru gxemul-0.6.2/src/Makefile.skel gxemul-0.7.0+dfsg/src/Makefile.skel --- gxemul-0.6.2/src/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/Makefile.skel 2021-11-27 09:42:23.000000000 +0000 @@ -5,16 +5,12 @@ all: do_include $(MAKE) the_rest -the_rest: do_components do_console do_cpus do_debugger do_devices do_disk \ - do_file do_machines do_main do_net do_old_main \ - do_promemul do_symbol do_ui +the_rest: do_console do_cpus do_debugger do_devices do_disk \ + do_file do_machines do_net do_core do_promemul do_symbol do_include: cd include; $(MAKE) -do_components: - cd components; $(MAKE) - do_console: cd console; $(MAKE) @@ -36,14 +32,11 @@ do_machines: cd machines; $(MAKE) -do_main: - cd main; $(MAKE) - do_net: cd net; $(MAKE) -do_old_main: - cd old_main; $(MAKE) +do_core: + cd core; $(MAKE) do_promemul: cd promemul; $(MAKE) @@ -51,17 +44,13 @@ do_symbol: cd symbol; $(MAKE) -do_ui: - cd ui; $(MAKE) - $(OBJS): Makefile clean: - rm -f $(OBJS) *core + rm -f $(OBJS) *.core cd include; $(MAKE) clean - cd components; $(MAKE) clean cd console; $(MAKE) clean cd cpus; $(MAKE) clean cd debugger; $(MAKE) clean @@ -69,16 +58,13 @@ cd disk; $(MAKE) clean cd file; $(MAKE) clean cd machines; $(MAKE) clean - cd main; $(MAKE) clean cd net; $(MAKE) clean - cd old_main; $(MAKE) clean + cd core; $(MAKE) clean cd promemul; $(MAKE) clean cd symbol; $(MAKE) clean - cd ui; $(MAKE) clean clean_all: clean cd include; $(MAKE) clean_all - cd components; $(MAKE) clean_all cd console; $(MAKE) clean_all cd cpus; $(MAKE) clean_all cd debugger; $(MAKE) clean_all @@ -86,12 +72,10 @@ cd disk; $(MAKE) clean_all cd file; $(MAKE) clean_all cd machines; $(MAKE) clean_all - cd main; $(MAKE) clean_all cd net; $(MAKE) clean_all - cd old_main; $(MAKE) clean_all + cd core; $(MAKE) clean_all cd promemul; $(MAKE) clean_all cd symbol; $(MAKE) clean_all - cd ui; $(MAKE) clean_all rm -f Makefile diff -Nru gxemul-0.6.2/src/net/Makefile.skel gxemul-0.7.0+dfsg/src/net/Makefile.skel --- gxemul-0.6.2/src/net/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/Makefile.skel 2021-11-27 09:42:23.000000000 +0000 @@ -2,9 +2,9 @@ # Makefile for GXemul src/net # -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) +CFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) -OBJS=net.o net_ip.o net_misc.o +OBJS=net.o net_ip.o net_misc.o net_tap.o net_ether.o all: $(OBJS) diff -Nru gxemul-0.6.2/src/net/net.c gxemul-0.7.0+dfsg/src/net/net.c --- gxemul-0.6.2/src/net/net.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,870 @@ +/* + * Copyright (C) 2004-2021 Anders Gavare. 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. The name of the author 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. + * + * + * Emulated network. + * + * (Read the README file in this directory for more details.) + * + * + * NOTE: The 'nic' argument used in many functions in this file is a pointer + * to the nic_data for each NIC, so that if multiple NICs are emulated + * concurrently, they will not get packets that are meant for some other + * controller. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "machine.h" +#include "misc.h" +#include "net.h" + + +/* + * net_allocate_ethernet_packet_link(): + * + * This routine allocates an ethernet_packet_link struct, and adds it at + * the end of the packet chain. A data buffer is allocated, and the data, + * nic, and len fields of the link are set. + * + * Note: The data buffer is not zeroed. + * + * Return value is a pointer to the link on success. It doesn't return on + * failure. + */ +struct ethernet_packet_link *net_allocate_ethernet_packet_link( + struct net *net, struct nic_data *nic, size_t len) +{ + struct ethernet_packet_link *lp; + + CHECK_ALLOCATION(lp = (struct ethernet_packet_link *) + malloc(sizeof(struct ethernet_packet_link))); + + lp->len = len; + lp->nic = nic; + CHECK_ALLOCATION(lp->data = (unsigned char *) malloc(len)); + + lp->next = NULL; + + /* Add last in the link chain: */ + lp->prev = net->last_ethernet_packet; + if (lp->prev != NULL) + lp->prev->next = lp; + else + net->first_ethernet_packet = lp; + net->last_ethernet_packet = lp; + + return lp; +} + + +/* + * net_arp(): + * + * Handle an ARP (or RARP) packet, coming from the emulated NIC. + * + * An ARP packet might look like this: + * + * ARP header: + * ARP hardware addr family: 0001 + * ARP protocol addr family: 0800 + * ARP addr lengths: 06 04 + * ARP request: 0001 + * ARP from: 112233445566 01020304 + * ARP to: 000000000000 01020301 + * + * An ARP request with a 'to' IP value of the gateway should cause an + * ARP response packet to be created. + * + * An ARP request with the same from and to IP addresses should be ignored. + * (This would be a host testing to see if there is an IP collision.) + */ +static void net_arp(struct net *net, struct nic_data *nic, + unsigned char *packet, int len, int reverse) +{ + int q; + int i; + + /* TODO: This debug dump assumes ethernet->IPv4 translation: */ + if (reverse) + debug("[ net: RARP: "); + else + debug("[ net: ARP: "); + for (i=0; i<2; i++) + debug("%02x", packet[i]); + debug(" "); + for (i=2; i<4; i++) + debug("%02x", packet[i]); + debug(" "); + debug("%02x", packet[4]); + debug(" "); + debug("%02x", packet[5]); + debug(" req="); + debug("%02x", packet[6]); /* Request type */ + debug("%02x", packet[7]); + debug(" from="); + for (i=8; i<18; i++) + debug("%02x", packet[i]); + debug(" to="); + for (i=18; i<28; i++) + debug("%02x", packet[i]); + debug(" ]\n"); + + if (packet[0] == 0x00 && packet[1] == 0x01 && + packet[2] == 0x08 && packet[3] == 0x00 && + packet[4] == 0x06 && packet[5] == 0x04) { + int r = (packet[6] << 8) + packet[7]; + struct ethernet_packet_link *lp; + + switch (r) { + case 1: /* Request */ + /* Only create a reply if this was meant for the + gateway: */ + if (memcmp(packet+24, net->gateway_ipv4_addr, 4) != 0) + break; + + lp = net_allocate_ethernet_packet_link( + net, nic, 60 + 14); + + /* Copy the old packet first: */ + memset(lp->data, 0, 60 + 14); + memcpy(lp->data + 14, packet, len); + + /* Add ethernet ARP header: */ + memcpy(lp->data + 0, lp->data + 8 + 14, 6); + memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); + lp->data[12] = 0x08; lp->data[13] = 0x06; + + /* Address of the emulated machine: */ + memcpy(lp->data + 18 + 14, lp->data + 8 + 14, 10); + + /* Address of the gateway: */ + memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr, + 6); + memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4); + + /* This is a Reply: */ + lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x02; + + break; + case 3: /* Reverse Request */ + lp = net_allocate_ethernet_packet_link( + net, nic, 60 + 14); + + /* Copy the old packet first: */ + memset(lp->data, 0, 60 + 14); + memcpy(lp->data + 14, packet, len); + + /* Add ethernet RARP header: */ + memcpy(lp->data + 0, packet + 8, 6); + memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); + lp->data[12] = 0x80; lp->data[13] = 0x35; + + /* This is a RARP reply: */ + lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x04; + + /* Address of the gateway: */ + memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr, + 6); + memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4); + + /* MAC address of emulated machine: */ + memcpy(lp->data + 18 + 14, packet + 8, 6); + + /* + * IP address of the emulated machine: Automagically + * generated from the MAC address. :-) + * + * packet+8 points to the client's mac address, + * for example 10:20:30:00:00:z0, where z is 0..15. + * 10:20:30:00:00:10 results in 10.0.0.1. + */ + /* q = (packet[8 + 3]) >> 4; */ + /* q = q*15 + ((packet[8 + 4]) >> 4); */ + q = (packet[8 + 5]) >> 4; + lp->data[24 + 14] = 10; + lp->data[25 + 14] = 0; + lp->data[26 + 14] = 0; + lp->data[27 + 14] = q; + break; + case 2: /* Reply */ + case 4: /* Reverse Reply */ + default: + debugmsg(SUBSYS_NET, "ARP", VERBOSITY_WARNING, + "UNIMPLEMENTED request type 0x%04x", r); + } + } else { + if (len >= 6) + debugmsg(SUBSYS_NET, "ARP", VERBOSITY_WARNING, + "UNIMPLEMENTED arp packet type: " + "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ...", + packet[0], packet[1], packet[2], packet[3], + packet[4], packet[5]); + } +} + + +/* + * net_ethernet_rx_avail(): + * + * Return 1 if there is a packet available for this nic, otherwise + * return 0. + * + * Appart from actually checking for incoming packets from the outside world, + * this function basically works like net_ethernet_rx() but it only receives + * a return value telling us whether there is a packet or not, we don't + * actually get the packet. + */ +int net_ethernet_rx_avail(struct net *net, struct nic_data *nic) +{ + if (net == NULL) + return 0; + + /* + * If we're using a tap device, check in with that and + * that's it. + */ + if (net->tapdev) { + net_tap_rx_avail(net); + return net_ethernet_rx(net, nic, NULL, NULL); + } + + /* + * If the network is distributed across multiple emulator processes, + * then receive incoming packets from those processes. + */ + if (net->local_port != 0) { + struct sockaddr_in si; + socklen_t si_len = sizeof(si); + int res, i, nreceived = 0; + unsigned char buf[60000]; + + do { + res = recvfrom(net->local_port_socket, buf, + sizeof(buf), 0, (struct sockaddr *)&si, &si_len); + + if (res != -1) { + nreceived ++; + + debugmsg(SUBSYS_NET, "RX avail", VERBOSITY_DEBUG, + "incoming DISTRIBUTED packet, %i " + "bytes from %s:%d\n", res, + inet_ntoa(si.sin_addr), + ntohs(si.sin_port)); + + /* Add the packet to all "our" NICs on this + network: */ + for (i=0; in_nics; i++) { + struct ethernet_packet_link *lp; + lp = net_allocate_ethernet_packet_link( + net, net->nic_data[i], res); + memcpy(lp->data, buf, res); + } + } + } while (res != -1 && nreceived < 100); + } + + /* IP protocol specific: */ + net_udp_rx_avail(net, nic); + net_tcp_rx_avail(net, nic); + + return net_ethernet_rx(net, nic, NULL, NULL); +} + + +/* + * net_ethernet_rx(): + * + * Receive an ethernet packet. (This means handing over an already prepared + * packet from this module to a specific ethernet controller device.) + * + * Return value is 1 if there was a packet available. *packetp and *lenp + * will be set to the packet's data pointer and length, respectively, and + * the packet will be removed from the linked list). If there was no packet + * available, 0 is returned. + * + * If packetp is NULL, then the search is aborted as soon as a packet with + * the correct 'nic' field is found, and a 1 is returned, but as packetp + * is NULL we can't return the actual packet. (This is the internal form + * if net_ethernet_rx_avail().) + */ +int net_ethernet_rx(struct net *net, struct nic_data *nic, + unsigned char **packetp, int *lenp) +{ + struct ethernet_packet_link *lp, *prev; + + if (net == NULL) + return 0; + + /* Find the first packet which has the right 'nic' field. */ + + lp = net->first_ethernet_packet; + prev = NULL; + while (lp != NULL) { + if (lp->nic == nic) { + /* We found a packet for this controller! */ + if (packetp == NULL || lenp == NULL) + return 1; + + /* Let's return it: */ + (*packetp) = lp->data; + (*lenp) = lp->len; + + /* Remove this link from the linked list: */ + if (prev == NULL) + net->first_ethernet_packet = lp->next; + else + prev->next = lp->next; + + if (lp->next == NULL) + net->last_ethernet_packet = prev; + else + lp->next->prev = prev; + + free(lp); + + /* ... and return successfully: */ + return 1; + } + + prev = lp; + lp = lp->next; + } + + /* No packet found. :-( */ + return 0; +} + + +/* + * net_ethernet_tx(): + * + * Transmit an ethernet packet, as seen from the emulated ethernet controller. + * If the packet can be handled here, it will not necessarily be transmitted + * to the outside world. + */ +void net_ethernet_tx(struct net *net, struct nic_data *nic, + unsigned char *packet, int len) +{ + int i, eth_type, for_the_gateway; + + if (net == NULL) + return; + + /* Drop too small packets: */ + if (len < 20) { + debugmsg(SUBSYS_NET, "TX", VERBOSITY_WARNING, + "Warning: dropping tiny packet (%i bytes) ]\n", len); + return; + } + + /* + * If we're using a tap device, we send the packet that way + * and that's it. + */ + if (net->tapdev) { + net_tap_tx(net, nic, packet, len); + return; + } + + for_the_gateway = !memcmp(packet, net->gateway_ethernet_addr, 6); + + /* + * Copy this packet to all other NICs on this network (except if + * it is aimed specifically at the gateway's ethernet address): + */ + if (!for_the_gateway && nic != NULL && net->n_nics > 0) { + for (i=0; in_nics; i++) + if (nic != net->nic_data[i]) { + struct ethernet_packet_link *lp; + lp = net_allocate_ethernet_packet_link(net, + net->nic_data[i], len); + + /* Copy the entire packet: */ + memcpy(lp->data, packet, len); + } + } + + /* + * If this network is distributed across multiple emulator processes, + * then transmit the packet to those other processes. + */ + if (!for_the_gateway && net->remote_nets != NULL) { + struct remote_net *rnp = net->remote_nets; + while (rnp != NULL) { + send_udp(&rnp->ipv4_addr, rnp->portnr, packet, len); + rnp = rnp->next; + } + } + + + /* + * The code below simulates the behaviour of a "NAT"-style gateway. + * + * Packets that are not destined for the gateway are dropped first: + * (DHCP packets are let through, though.) + */ + + if (!for_the_gateway && packet[0] != 0xff && + !(packet[0] == 0x00 && packet[5] == 0x00)) + return; + + eth_type = (packet[12] << 8) + packet[13]; + + /* IP: */ + if (eth_type == ETHERTYPE_IP) { + /* Routed via the gateway? */ + if (for_the_gateway) { + net_ip(net, nic, packet, len); + return; + } + + /* Broadcast? (DHCP does this.) */ + if (packet[0] == 0xff && packet[1] == 0xff && + packet[2] == 0xff && packet[3] == 0xff && + packet[4] == 0xff && packet[5] == 0xff) { + net_ip_broadcast(net, nic, packet, len); + return; + } + + if (net->n_nics < 2) { + debugmsg(SUBSYS_NET, "TX", VERBOSITY_WARNING, + "IP packet not for gateway, " + "and not broadcast: %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x ", + packet[0], packet[1], packet[2], packet[3], + packet[4], packet[5], packet[6], packet[7], + packet[8], packet[9], + packet[10], packet[11], packet[12], packet[13]); + } + return; + } + + /* ARP: */ + if (eth_type == ETHERTYPE_ARP) { + if (len != 42 && len != 60) + debugmsg(SUBSYS_NET, "TX", VERBOSITY_WARNING, + "unusual ARP len (%i)", len); + net_arp(net, nic, packet + 14, len - 14, 0); + return; + } + + /* RARP: */ + if (eth_type == ETHERTYPE_REVARP) { + net_arp(net, nic, packet + 14, len - 14, 1); + return; + } + + /* Sprite: */ + if (eth_type == ETHERTYPE_SPRITE) { + /* TODO. */ + debugmsg(SUBSYS_NET, "TX", VERBOSITY_WARNING, + "UNIMPLEMENTED Sprite packet"); + return; + } + + /* IPv6: */ + if (eth_type == ETHERTYPE_IPV6) { + /* TODO. */ + debugmsg(SUBSYS_NET, "TX", VERBOSITY_WARNING, + "IPv6 is not yet implemented!"); + return; + } + + debugmsg(SUBSYS_NET, "TX", VERBOSITY_WARNING, + "ethernet packet type 0x%04x not yet implemented", eth_type); +} + + +/* + * parse_resolvconf(): + * + * This function parses "/etc/resolv.conf" to figure out the nameserver + * and domain used by the host. + */ +static void parse_resolvconf(struct net *net) +{ + FILE *f; + char buf[8000]; + size_t len; + int res; + unsigned int i, start; + + /* + * This is a very ugly hack, which tries to figure out which + * nameserver the host uses by looking for the string 'nameserver' + * in /etc/resolv.conf. + * + * This can later on be used for DHCP autoconfiguration. (TODO) + * + * TODO: This is hardcoded to use /etc/resolv.conf. Not all + * operating systems use that filename. + * + * TODO: This is hardcoded for AF_INET (that is, IPv4). + * + * TODO: This assumes that the first nameserver listed is the + * one to use. + */ + f = fopen("/etc/resolv.conf", "r"); + if (f == NULL) + return; + + /* TODO: get rid of the hardcoded values */ + memset(buf, 0, sizeof(buf)); + len = fread(buf, 1, sizeof(buf) - 100, f); + fclose(f); + buf[sizeof(buf) - 1] = '\0'; + + for (i=0; i= len) + break; + start = i; + + p = buf+start; + while ((*p >= '0' && *p <= '9') || *p == '.') + p++; + *p = '\0'; + +#ifdef HAVE_INET_PTON + res = inet_pton(AF_INET, buf + start, + &net->nameserver_ipv4); +#else + res = inet_aton(buf + start, &net->nameserver_ipv4); +#endif + if (res < 1) + break; + + net->nameserver_known = 1; + break; + } +} + + +/* + * net_add_nic(): + * + * Add a NIC to a network. (All NICs on a network will see each other's + * packets.) + */ +void net_add_nic(struct net *net, struct nic_data *nic) +{ + if (net == NULL) + return; + + if (nic == NULL) { + fprintf(stderr, "net_add_nic(): nic = NULL\n"); + exit(1); + } + + /* + * Set up some of the basics for this NIC. We assume the + * device has set up all of the other fields. + */ + nic->net = net; + nic->promiscuous_mode = 0; + + net->n_nics++; + CHECK_ALLOCATION(net->nic_data = (struct nic_data **) + realloc(net->nic_data, sizeof(struct nic_data *) * net->n_nics)); + + net->nic_data[net->n_nics - 1] = nic; +} + + +/* + * net_gateway_init(): + * + * This function creates a "gateway" machine (for example at IPv4 address + * 10.0.0.254, if the net is 10.0.0.0/8), which acts as a gateway/router/ + * nameserver etc. + */ +static void net_gateway_init(struct net *net) +{ + unsigned char *p = (unsigned char *) &net->netmask_ipv4; + uint32_t x; + int xl; + + x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; + xl = 32 - net->netmask_ipv4_len; + if (xl > 8) + xl = 8; + x |= ((1 << xl) - 1) & ~1; + + net->gateway_ipv4_addr[0] = x >> 24; + net->gateway_ipv4_addr[1] = x >> 16; + net->gateway_ipv4_addr[2] = x >> 8; + net->gateway_ipv4_addr[3] = x; + + net->gateway_ethernet_addr[0] = 0x60; + net->gateway_ethernet_addr[1] = 0x50; + net->gateway_ethernet_addr[2] = 0x40; + net->gateway_ethernet_addr[3] = 0x30; + net->gateway_ethernet_addr[4] = 0x20; + net->gateway_ethernet_addr[5] = 0x10; +} + + +/* + * net_dumpinfo(): + * + * Called from the debugger's "machine" command, to print some info about + * a network. + */ +void net_dumpinfo(struct net *net) +{ + int iadd = 1; + struct remote_net *rnp; + + debugmsg(SUBSYS_NET, "", VERBOSITY_INFO, ""); + + debug_indentation(iadd); + + if (net->tapdev) { + debugmsg(SUBSYS_NET, "tap", VERBOSITY_INFO, + "using device %s", net->tapdev); + debug_indentation(-iadd); + return; + } + + debugmsg(SUBSYS_NET, "simulated network", VERBOSITY_INFO, ""); + + debug_indentation(iadd); + + net_debugaddr(&net->netmask_ipv4, NET_ADDR_IPV4); + debug("/%i", net->netmask_ipv4_len); + + debug(" (max outgoing: TCP=%i, UDP=%i)\n", + MAX_TCP_CONNECTIONS, MAX_UDP_CONNECTIONS); + + debug("gateway+nameserver: "); + net_debugaddr(&net->gateway_ipv4_addr, NET_ADDR_IPV4); + debug(" ("); + net_debugaddr(&net->gateway_ethernet_addr, NET_ADDR_ETHERNET); + debug(")\n"); + + if (!net->nameserver_known) { + debug("(could not determine real nameserver from /etc/resolv.conf)\n"); + } else { + debug("nameserver uses real nameserver "); + net_debugaddr(&net->nameserver_ipv4, NET_ADDR_IPV4); + debug("\n"); + } + + rnp = net->remote_nets; + if (net->local_port != 0) + debug("distributed network: local port = %i\n", + net->local_port); + debug_indentation(iadd); + while (rnp != NULL) { + debug("remote \"%s\": ", rnp->name); + net_debugaddr(&rnp->ipv4_addr, NET_ADDR_IPV4); + debug(" port %i\n", rnp->portnr); + rnp = rnp->next; + } + debug_indentation(-iadd); + + debug_indentation(-iadd); + debug_indentation(-iadd); +} + + +/* + * net_init(): + * + * This function creates a network, and returns a pointer to it. + * + * ipv4addr should be something like "10.0.0.0", netipv4len = 8. + * + * If n_remote is more than zero, remote should be a pointer to an array + * of strings of the following format: "host:portnr". + * + * Network settings are registered if settings_prefix is non-NULL. + * (The one calling net_init() is also responsible for calling net_deinit().) + * + * On failure, NULL is returned. + */ +struct net *net_init(struct emul *emul, int init_flags, + const char *tapdev, + const char *ipv4addr, int netipv4len, + char **remote, int n_remote, int local_port, + const char *settings_prefix) +{ + struct net *net; + int res; + + CHECK_ALLOCATION(net = (struct net *) malloc(sizeof(struct net))); + memset(net, 0, sizeof(struct net)); + + /* Set the back pointer: */ + net->emul = emul; + + /* Sane defaults: */ + net->timestamp = 0; + net->first_ethernet_packet = net->last_ethernet_packet = NULL; + net->tapdev = NULL; + net->tap_fd = -1; + + /* + * If we're using a tap device, attempt to initialize it and + * none of the other stuff. + */ + if (tapdev) { + if (!net_tap_init(net, tapdev)) { + free(net); + return NULL; + } + + net_dumpinfo(net); + return net; + } + +#ifdef HAVE_INET_PTON + res = inet_pton(AF_INET, ipv4addr, &net->netmask_ipv4); +#else + res = inet_aton(ipv4addr, &net->netmask_ipv4); +#endif + if (res < 1) { + fprintf(stderr, "net_init(): could not parse IPv4 address" + " '%s'\n", ipv4addr); + free(net); + return NULL; + } + + if (netipv4len < 1 || netipv4len > 30) { + fprintf(stderr, "net_init(): extremely weird ipv4 " + "network length (%i)\n", netipv4len); + free(net); + return NULL; + } + + net->netmask_ipv4_len = netipv4len; + + net->nameserver_known = 0; + parse_resolvconf(net); + + /* Distributed network? Then add remote hosts: */ + if (local_port != 0) { + struct sockaddr_in si_self; + + net->local_port = local_port; + net->local_port_socket = socket(AF_INET, SOCK_DGRAM, 0); + if (net->local_port_socket < 0) { + perror("socket"); + free(net); + return NULL; + } + + memset((char *)&si_self, 0, sizeof(si_self)); + si_self.sin_family = AF_INET; + si_self.sin_port = htons(local_port); + si_self.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(net->local_port_socket, (struct sockaddr *)&si_self, + sizeof(si_self)) < 0) { + perror("bind"); + free(net); + return NULL; + } + + /* Set the socket to non-blocking: */ + res = fcntl(net->local_port_socket, F_GETFL); + fcntl(net->local_port_socket, F_SETFL, res | O_NONBLOCK); + } + if (n_remote != 0) { + struct remote_net *rnp; + while ((n_remote--) != 0) { + struct hostent *hp; + + /* debug("adding '%s'\n", remote[n_remote]); */ + CHECK_ALLOCATION(rnp = (struct remote_net *) + malloc(sizeof(struct remote_net))); + memset(rnp, 0, sizeof(struct remote_net)); + + rnp->next = net->remote_nets; + net->remote_nets = rnp; + + CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote])); + if (strchr(rnp->name, ':') != NULL) + strchr(rnp->name, ':')[0] = '\0'; + + hp = gethostbyname(rnp->name); + if (hp == NULL) { + fprintf(stderr, "could not resolve '%s'\n", + rnp->name); + free(net); + return NULL; + } + + memcpy(&rnp->ipv4_addr, hp->h_addr, hp->h_length); + free(rnp->name); + + /* And again: */ + CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote])); + if (strchr(rnp->name, ':') == NULL) { + fprintf(stderr, "Remote network '%s' is not " + "'host:portnr'?\n", rnp->name); + free(net); + return NULL; + } + + rnp->portnr = atoi(strchr(rnp->name, ':') + 1); + } + } + + if (init_flags & NET_INIT_FLAG_GATEWAY) + net_gateway_init(net); + + net_dumpinfo(net); + + /* This is necessary when using the real network: */ + signal(SIGPIPE, SIG_IGN); + + return net; +} + diff -Nru gxemul-0.6.2/src/net/net.cc gxemul-0.7.0+dfsg/src/net/net.cc --- gxemul-0.6.2/src/net/net.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,832 +0,0 @@ -/* - * Copyright (C) 2004-2009 Anders Gavare. 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. The name of the author 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. - * - * - * Emulated network. - * - * (Read the README file in this directory for more details.) - * - * - * NOTE: The 'extra' argument used in many functions in this file is a pointer - * to something unique for each NIC (i.e. the NIC itself :-), so that if - * multiple NICs are emulated concurrently, they will not get packets that - * are meant for some other controller. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "machine.h" -#include "misc.h" -#include "net.h" - - -/* #define debug fatal */ - - -/* - * net_allocate_ethernet_packet_link(): - * - * This routine allocates an ethernet_packet_link struct, and adds it at - * the end of the packet chain. A data buffer is allocated, and the data, - * extra, and len fields of the link are set. - * - * Note: The data buffer is not zeroed. - * - * Return value is a pointer to the link on success. It doesn't return on - * failure. - */ -struct ethernet_packet_link *net_allocate_ethernet_packet_link( - struct net *net, void *extra, size_t len) -{ - struct ethernet_packet_link *lp; - - CHECK_ALLOCATION(lp = (struct ethernet_packet_link *) - malloc(sizeof(struct ethernet_packet_link))); - - lp->len = len; - lp->extra = extra; - CHECK_ALLOCATION(lp->data = (unsigned char *) malloc(len)); - - lp->next = NULL; - - /* Add last in the link chain: */ - lp->prev = net->last_ethernet_packet; - if (lp->prev != NULL) - lp->prev->next = lp; - else - net->first_ethernet_packet = lp; - net->last_ethernet_packet = lp; - - return lp; -} - - -/* - * net_arp(): - * - * Handle an ARP (or RARP) packet, coming from the emulated NIC. - * - * An ARP packet might look like this: - * - * ARP header: - * ARP hardware addr family: 0001 - * ARP protocol addr family: 0800 - * ARP addr lengths: 06 04 - * ARP request: 0001 - * ARP from: 112233445566 01020304 - * ARP to: 000000000000 01020301 - * - * An ARP request with a 'to' IP value of the gateway should cause an - * ARP response packet to be created. - * - * An ARP request with the same from and to IP addresses should be ignored. - * (This would be a host testing to see if there is an IP collision.) - */ -static void net_arp(struct net *net, void *extra, - unsigned char *packet, int len, int reverse) -{ - int q; - int i; - - /* TODO: This debug dump assumes ethernet->IPv4 translation: */ - if (reverse) - debug("[ net: RARP: "); - else - debug("[ net: ARP: "); - for (i=0; i<2; i++) - debug("%02x", packet[i]); - debug(" "); - for (i=2; i<4; i++) - debug("%02x", packet[i]); - debug(" "); - debug("%02x", packet[4]); - debug(" "); - debug("%02x", packet[5]); - debug(" req="); - debug("%02x", packet[6]); /* Request type */ - debug("%02x", packet[7]); - debug(" from="); - for (i=8; i<18; i++) - debug("%02x", packet[i]); - debug(" to="); - for (i=18; i<28; i++) - debug("%02x", packet[i]); - debug(" ]\n"); - - if (packet[0] == 0x00 && packet[1] == 0x01 && - packet[2] == 0x08 && packet[3] == 0x00 && - packet[4] == 0x06 && packet[5] == 0x04) { - int r = (packet[6] << 8) + packet[7]; - struct ethernet_packet_link *lp; - - switch (r) { - case 1: /* Request */ - /* Only create a reply if this was meant for the - gateway: */ - if (memcmp(packet+24, net->gateway_ipv4_addr, 4) != 0) - break; - - lp = net_allocate_ethernet_packet_link( - net, extra, 60 + 14); - - /* Copy the old packet first: */ - memset(lp->data, 0, 60 + 14); - memcpy(lp->data + 14, packet, len); - - /* Add ethernet ARP header: */ - memcpy(lp->data + 0, lp->data + 8 + 14, 6); - memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); - lp->data[12] = 0x08; lp->data[13] = 0x06; - - /* Address of the emulated machine: */ - memcpy(lp->data + 18 + 14, lp->data + 8 + 14, 10); - - /* Address of the gateway: */ - memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr, - 6); - memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4); - - /* This is a Reply: */ - lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x02; - - break; - case 3: /* Reverse Request */ - lp = net_allocate_ethernet_packet_link( - net, extra, 60 + 14); - - /* Copy the old packet first: */ - memset(lp->data, 0, 60 + 14); - memcpy(lp->data + 14, packet, len); - - /* Add ethernet RARP header: */ - memcpy(lp->data + 0, packet + 8, 6); - memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); - lp->data[12] = 0x80; lp->data[13] = 0x35; - - /* This is a RARP reply: */ - lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x04; - - /* Address of the gateway: */ - memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr, - 6); - memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4); - - /* MAC address of emulated machine: */ - memcpy(lp->data + 18 + 14, packet + 8, 6); - - /* - * IP address of the emulated machine: Automagically - * generated from the MAC address. :-) - * - * packet+8 points to the client's mac address, - * for example 10:20:30:00:00:z0, where z is 0..15. - * 10:20:30:00:00:10 results in 10.0.0.1. - */ - /* q = (packet[8 + 3]) >> 4; */ - /* q = q*15 + ((packet[8 + 4]) >> 4); */ - q = (packet[8 + 5]) >> 4; - lp->data[24 + 14] = 10; - lp->data[25 + 14] = 0; - lp->data[26 + 14] = 0; - lp->data[27 + 14] = q; - break; - case 2: /* Reply */ - case 4: /* Reverse Reply */ - default: - fatal("[ net: ARP: UNIMPLEMENTED request type " - "0x%04x ]\n", r); - } - } else { - fatal("[ net: ARP: UNIMPLEMENTED arp packet type: "); - for (i=0; ilocal_port != 0) { - struct sockaddr_in si; - socklen_t si_len = sizeof(si); - int res, i, nreceived = 0; - unsigned char buf[60000]; - - do { - res = recvfrom(net->local_port_socket, buf, - sizeof(buf), 0, (struct sockaddr *)&si, &si_len); - - if (res != -1) { - nreceived ++; - - /* fatal("[ incoming DISTRIBUTED packet, %i " - "bytes from %s:%d\n", res, - inet_ntoa(si.sin_addr), - ntohs(si.sin_port)); */ - - /* Add the packet to all "our" NICs on this - network: */ - for (i=0; in_nics; i++) { - struct ethernet_packet_link *lp; - lp = net_allocate_ethernet_packet_link( - net, net->nic_extra[i], res); - memcpy(lp->data, buf, res); - } - } - } while (res != -1 && nreceived < 100); - } - - /* IP protocol specific: */ - net_udp_rx_avail(net, extra); - net_tcp_rx_avail(net, extra); - - return net_ethernet_rx(net, extra, NULL, NULL); -} - - -/* - * net_ethernet_rx(): - * - * Receive an ethernet packet. (This means handing over an already prepared - * packet from this module to a specific ethernet controller device.) - * - * Return value is 1 if there was a packet available. *packetp and *lenp - * will be set to the packet's data pointer and length, respectively, and - * the packet will be removed from the linked list). If there was no packet - * available, 0 is returned. - * - * If packetp is NULL, then the search is aborted as soon as a packet with - * the correct 'extra' field is found, and a 1 is returned, but as packetp - * is NULL we can't return the actual packet. (This is the internal form - * if net_ethernet_rx_avail().) - */ -int net_ethernet_rx(struct net *net, void *extra, - unsigned char **packetp, int *lenp) -{ - struct ethernet_packet_link *lp, *prev; - - if (net == NULL) - return 0; - - /* Find the first packet which has the right 'extra' field. */ - - lp = net->first_ethernet_packet; - prev = NULL; - while (lp != NULL) { - if (lp->extra == extra) { - /* We found a packet for this controller! */ - if (packetp == NULL || lenp == NULL) - return 1; - - /* Let's return it: */ - (*packetp) = lp->data; - (*lenp) = lp->len; - - /* Remove this link from the linked list: */ - if (prev == NULL) - net->first_ethernet_packet = lp->next; - else - prev->next = lp->next; - - if (lp->next == NULL) - net->last_ethernet_packet = prev; - else - lp->next->prev = prev; - - free(lp); - - /* ... and return successfully: */ - return 1; - } - - prev = lp; - lp = lp->next; - } - - /* No packet found. :-( */ - return 0; -} - - -/* - * net_ethernet_tx(): - * - * Transmit an ethernet packet, as seen from the emulated ethernet controller. - * If the packet can be handled here, it will not necessarily be transmitted - * to the outside world. - */ -void net_ethernet_tx(struct net *net, void *extra, - unsigned char *packet, int len) -{ - int i, eth_type, for_the_gateway; - - if (net == NULL) - return; - - for_the_gateway = !memcmp(packet, net->gateway_ethernet_addr, 6); - - /* Drop too small packets: */ - if (len < 20) { - fatal("[ net_ethernet_tx: Warning: dropping tiny packet " - "(%i bytes) ]\n", len); - return; - } - - /* - * Copy this packet to all other NICs on this network (except if - * it is aimed specifically at the gateway's ethernet address): - */ - if (!for_the_gateway && extra != NULL && net->n_nics > 0) { - for (i=0; in_nics; i++) - if (extra != net->nic_extra[i]) { - struct ethernet_packet_link *lp; - lp = net_allocate_ethernet_packet_link(net, - net->nic_extra[i], len); - - /* Copy the entire packet: */ - memcpy(lp->data, packet, len); - } - } - - /* - * If this network is distributed across multiple emulator processes, - * then transmit the packet to those other processes. - */ - if (!for_the_gateway && net->remote_nets != NULL) { - struct remote_net *rnp = net->remote_nets; - while (rnp != NULL) { - send_udp(&rnp->ipv4_addr, rnp->portnr, packet, len); - rnp = rnp->next; - } - } - - - /* - * The code below simulates the behaviour of a "NAT"-style gateway. - * - * Packets that are not destined for the gateway are dropped first: - * (DHCP packets are let through, though.) - */ - - if (!for_the_gateway && packet[0] != 0xff && packet[0] != 0x00) - return; - -#if 0 - fatal("[ net: ethernet: "); - for (i=0; i<6; i++) fatal("%02x", packet[i]); fatal(" "); - for (i=6; i<12; i++) fatal("%02x", packet[i]); fatal(" "); - for (i=12; i<14; i++) fatal("%02x", packet[i]); fatal(" "); - for (i=14; in_nics < 2) { - fatal("[ net_ethernet_tx: IP packet not for gateway, " - "and not broadcast: "); - for (i=0; i<14; i++) - fatal("%02x", packet[i]); - fatal(" ]\n"); - } - return; - } - - /* ARP: */ - if (eth_type == ETHERTYPE_ARP) { - if (len != 42 && len != 60) - fatal("[ net_ethernet_tx: WARNING! unusual " - "ARP len (%i) ]\n", len); - net_arp(net, extra, packet + 14, len - 14, 0); - return; - } - - /* RARP: */ - if (eth_type == ETHERTYPE_REVARP) { - net_arp(net, extra, packet + 14, len - 14, 1); - return; - } - - /* Sprite: */ - if (eth_type == ETHERTYPE_SPRITE) { - /* TODO. */ - fatal("[ net: TX: UNIMPLEMENTED Sprite packet ]\n"); - return; - } - - /* IPv6: */ - if (eth_type == ETHERTYPE_IPV6) { - /* TODO. */ - fatal("[ net_ethernet_tx: IPv6 is not implemented yet! ]\n"); - return; - } - - fatal("[ net_ethernet_tx: ethernet packet type 0x%04x not yet " - "implemented ]\n", eth_type); -} - - -/* - * parse_resolvconf(): - * - * This function parses "/etc/resolv.conf" to figure out the nameserver - * and domain used by the host. - */ -static void parse_resolvconf(struct net *net) -{ - FILE *f; - char buf[8000]; - size_t len; - int res; - unsigned int i, start; - - /* - * This is a very ugly hack, which tries to figure out which - * nameserver the host uses by looking for the string 'nameserver' - * in /etc/resolv.conf. - * - * This can later on be used for DHCP autoconfiguration. (TODO) - * - * TODO: This is hardcoded to use /etc/resolv.conf. Not all - * operating systems use that filename. - * - * TODO: This is hardcoded for AF_INET (that is, IPv4). - * - * TODO: This assumes that the first nameserver listed is the - * one to use. - */ - f = fopen("/etc/resolv.conf", "r"); - if (f == NULL) - return; - - /* TODO: get rid of the hardcoded values */ - memset(buf, 0, sizeof(buf)); - len = fread(buf, 1, sizeof(buf) - 100, f); - fclose(f); - buf[sizeof(buf) - 1] = '\0'; - - for (i=0; i= len) - break; - start = i; - - p = buf+start; - while ((*p >= '0' && *p <= '9') || *p == '.') - p++; - *p = '\0'; - -#ifdef HAVE_INET_PTON - res = inet_pton(AF_INET, buf + start, - &net->nameserver_ipv4); -#else - res = inet_aton(buf + start, &net->nameserver_ipv4); -#endif - if (res < 1) - break; - - net->nameserver_known = 1; - break; - } - - for (i=0; i= len) - break; - - start = i; - while (idomain_name = strdup(buf+start)); - break; - } -} - - -/* - * net_add_nic(): - * - * Add a NIC to a network. (All NICs on a network will see each other's - * packets.) - */ -void net_add_nic(struct net *net, void *extra, unsigned char *macaddr) -{ - if (net == NULL) - return; - - if (extra == NULL) { - fprintf(stderr, "net_add_nic(): extra = NULL\n"); - exit(1); - } - - net->n_nics ++; - CHECK_ALLOCATION(net->nic_extra = (void **) - realloc(net->nic_extra, sizeof(void *) * net->n_nics)); - - net->nic_extra[net->n_nics - 1] = extra; -} - - -/* - * net_gateway_init(): - * - * This function creates a "gateway" machine (for example at IPv4 address - * 10.0.0.254, if the net is 10.0.0.0/8), which acts as a gateway/router/ - * nameserver etc. - */ -static void net_gateway_init(struct net *net) -{ - unsigned char *p = (unsigned char *) &net->netmask_ipv4; - uint32_t x; - int xl; - - x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; - xl = 32 - net->netmask_ipv4_len; - if (xl > 8) - xl = 8; - x |= ((1 << xl) - 1) & ~1; - - net->gateway_ipv4_addr[0] = x >> 24; - net->gateway_ipv4_addr[1] = x >> 16; - net->gateway_ipv4_addr[2] = x >> 8; - net->gateway_ipv4_addr[3] = x; - - net->gateway_ethernet_addr[0] = 0x60; - net->gateway_ethernet_addr[1] = 0x50; - net->gateway_ethernet_addr[2] = 0x40; - net->gateway_ethernet_addr[3] = 0x30; - net->gateway_ethernet_addr[4] = 0x20; - net->gateway_ethernet_addr[5] = 0x10; -} - - -/* - * net_dumpinfo(): - * - * Called from the debugger's "machine" command, to print some info about - * a network. - */ -void net_dumpinfo(struct net *net) -{ - int iadd = DEBUG_INDENTATION; - struct remote_net *rnp; - - debug("net:\n"); - - debug_indentation(iadd); - - debug("simulated network: "); - net_debugaddr(&net->netmask_ipv4, NET_ADDR_IPV4); - debug("/%i", net->netmask_ipv4_len); - - debug(" (max outgoing: TCP=%i, UDP=%i)\n", - MAX_TCP_CONNECTIONS, MAX_UDP_CONNECTIONS); - - debug("simulated gateway+nameserver: "); - net_debugaddr(&net->gateway_ipv4_addr, NET_ADDR_IPV4); - debug(" ("); - net_debugaddr(&net->gateway_ethernet_addr, NET_ADDR_ETHERNET); - debug(")\n"); - - if (!net->nameserver_known) { - debug("(could not determine nameserver)\n"); - } else { - debug("simulated nameserver uses real nameserver "); - net_debugaddr(&net->nameserver_ipv4, NET_ADDR_IPV4); - debug("\n"); - } - - if (net->domain_name != NULL && net->domain_name[0]) - debug("domain: %s\n", net->domain_name); - - rnp = net->remote_nets; - if (net->local_port != 0) - debug("distributed network: local port = %i\n", - net->local_port); - debug_indentation(iadd); - while (rnp != NULL) { - debug("remote \"%s\": ", rnp->name); - net_debugaddr(&rnp->ipv4_addr, NET_ADDR_IPV4); - debug(" port %i\n", rnp->portnr); - rnp = rnp->next; - } - debug_indentation(-iadd); - - debug_indentation(-iadd); -} - - -/* - * net_init(): - * - * This function creates a network, and returns a pointer to it. - * - * ipv4addr should be something like "10.0.0.0", netipv4len = 8. - * - * If n_remote is more than zero, remote should be a pointer to an array - * of strings of the following format: "host:portnr". - * - * Network settings are registered if settings_prefix is non-NULL. - * (The one calling net_init() is also responsible for calling net_deinit().) - * - * On failure, exit() is called. - */ -struct net *net_init(struct emul *emul, int init_flags, - const char *ipv4addr, int netipv4len, - char **remote, int n_remote, int local_port, - const char *settings_prefix) -{ - struct net *net; - int res; - - CHECK_ALLOCATION(net = (struct net *) malloc(sizeof(struct net))); - memset(net, 0, sizeof(struct net)); - - /* Set the back pointer: */ - net->emul = emul; - - /* Sane defaults: */ - net->timestamp = 0; - net->first_ethernet_packet = net->last_ethernet_packet = NULL; - -#ifdef HAVE_INET_PTON - res = inet_pton(AF_INET, ipv4addr, &net->netmask_ipv4); -#else - res = inet_aton(ipv4addr, &net->netmask_ipv4); -#endif - if (res < 1) { - fprintf(stderr, "net_init(): could not parse IPv4 address" - " '%s'\n", ipv4addr); - exit(1); - } - - if (netipv4len < 1 || netipv4len > 30) { - fprintf(stderr, "net_init(): extremely weird ipv4 " - "network length (%i)\n", netipv4len); - exit(1); - } - net->netmask_ipv4_len = netipv4len; - - net->nameserver_known = 0; - net->domain_name = strdup(""); - parse_resolvconf(net); - - /* Distributed network? Then add remote hosts: */ - if (local_port != 0) { - struct sockaddr_in si_self; - - net->local_port = local_port; - net->local_port_socket = socket(AF_INET, SOCK_DGRAM, 0); - if (net->local_port_socket < 0) { - perror("socket"); - exit(1); - } - - memset((char *)&si_self, 0, sizeof(si_self)); - si_self.sin_family = AF_INET; - si_self.sin_port = htons(local_port); - si_self.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(net->local_port_socket, (struct sockaddr *)&si_self, - sizeof(si_self)) < 0) { - perror("bind"); - exit(1); - } - - /* Set the socket to non-blocking: */ - res = fcntl(net->local_port_socket, F_GETFL); - fcntl(net->local_port_socket, F_SETFL, res | O_NONBLOCK); - } - if (n_remote != 0) { - struct remote_net *rnp; - while ((n_remote--) != 0) { - struct hostent *hp; - - /* debug("adding '%s'\n", remote[n_remote]); */ - CHECK_ALLOCATION(rnp = (struct remote_net *) - malloc(sizeof(struct remote_net))); - memset(rnp, 0, sizeof(struct remote_net)); - - rnp->next = net->remote_nets; - net->remote_nets = rnp; - - CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote])); - if (strchr(rnp->name, ':') != NULL) - strchr(rnp->name, ':')[0] = '\0'; - - hp = gethostbyname(rnp->name); - if (hp == NULL) { - fprintf(stderr, "could not resolve '%s'\n", - rnp->name); - exit(1); - } - memcpy(&rnp->ipv4_addr, hp->h_addr, hp->h_length); - free(rnp->name); - - /* And again: */ - CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote])); - if (strchr(rnp->name, ':') == NULL) { - fprintf(stderr, "Remote network '%s' is not " - "'host:portnr'?\n", rnp->name); - exit(1); - } - rnp->portnr = atoi(strchr(rnp->name, ':') + 1); - } - } - - if (init_flags & NET_INIT_FLAG_GATEWAY) - net_gateway_init(net); - - net_dumpinfo(net); - - /* This is necessary when using the real network: */ - signal(SIGPIPE, SIG_IGN); - - return net; -} - diff -Nru gxemul-0.6.2/src/net/net_ether.c gxemul-0.7.0+dfsg/src/net/net_ether.c --- gxemul-0.6.2/src/net/net_ether.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net_ether.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2020 Jason R. Thorpe. 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. The name of the author 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. + */ + +/* + * Common Ethernet support routines. + */ + +#include +#include + +#include "misc.h" +#include "net.h" + + +/* + * net_ether_eq(): + * + * Compare two Ethernet addresses for equality. + */ +int net_ether_eq(const uint8_t *a1, const uint8_t *a2) +{ + + return a1[5] == a2[5] && + a1[4] == a2[4] && + a1[3] == a2[3] && + a1[2] == a2[2] && + a1[1] == a2[1] && + a1[0] == a2[0]; +} + + +/* + * net_ether_broadcast(): + * + * Returns 1 if the specified destination address is the Ethernet + * broadcast address. + */ +int net_ether_broadcast(const uint8_t *a) +{ + static const uint8_t ether_broadcast[6] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + return net_ether_eq(a, ether_broadcast); +} + + +/* + * net_ether_multicast(): + * + * Returns 1 if the specfied destination address is an Ethernet + * multicast address. + * + * Note that this also matches Ethernet broadcast, which is just + * a special case of multicast. + */ +int net_ether_multicast(const uint8_t *a) +{ + return (*a & 0x01); +} + + +/* + * Copyright (c) 1982, 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. 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. + * + * @(#)if_ethersubr.c 8.2 (Berkeley) 4/4/96 + */ + + +/* + * net_ether_crc32_le(): + * + * Fast table-driven little-endian Ethernet CRC generator. + */ +uint32_t net_ether_crc32_le(const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + uint32_t crc; + size_t i; + + crc = 0xffffffffU; /* initial value */ + + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + + return crc; +} diff -Nru gxemul-0.6.2/src/net/net_ip.c gxemul-0.7.0+dfsg/src/net/net_ip.c --- gxemul-0.6.2/src/net/net_ip.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net_ip.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,1586 @@ +/* + * Copyright (C) 2004-2021 Anders Gavare. 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. The name of the author 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. + * + * + * Internet Protocol related networking stuff. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "misc.h" +#include "net.h" + + +/* #define debug fatal */ +static int net_ip_debug = 0; // replace by debugmsg(....) + + + +/* + * net_ip_checksum(): + * + * Fill in an IP header checksum. (This works for ICMP too.) + * chksumoffset should be 10 for IP headers, and len = 20. + * For ICMP packets, chksumoffset = 2 and len = length of the ICMP packet. + */ +void net_ip_checksum(unsigned char *ip_header, int chksumoffset, int len) +{ + int i; + uint32_t sum = 0; + + for (i=0; i 65535) { + int to_add = sum >> 16; + sum = (sum & 0xffff) + to_add; + } + } + + sum ^= 0xffff; + ip_header[chksumoffset + 0] = sum >> 8; + ip_header[chksumoffset + 1] = sum & 0xff; +} + + +/* + * net_ip_tcp_checksum(): + * + * Fill in a TCP header checksum. This differs slightly from the IP + * checksum. The checksum is calculated on a pseudo header, the actual + * TCP header, and the data. This is what the pseudo header looks like: + * + * uint32_t srcaddr; + * uint32_t dstaddr; + * uint16_t protocol; (= 6 for tcp) + * uint16_t tcp_len; + * + * tcp_len is length of header PLUS data. The psedo header is created + * internally here, and does not need to be supplied by the caller. + */ +void net_ip_tcp_checksum(unsigned char *tcp_header, int chksumoffset, + int tcp_len, unsigned char *srcaddr, unsigned char *dstaddr, + int udpflag) +{ + int i, pad = 0; + unsigned char pseudoh[12]; + uint32_t sum = 0; + + memcpy(pseudoh + 0, srcaddr, 4); + memcpy(pseudoh + 4, dstaddr, 4); + pseudoh[8] = 0x00; + pseudoh[9] = udpflag? 17 : 6; + pseudoh[10] = tcp_len >> 8; + pseudoh[11] = tcp_len & 255; + + for (i=0; i<12; i+=2) { + uint16_t w = (pseudoh[i] << 8) + pseudoh[i+1]; + sum += w; + while (sum > 65535) { + int to_add = sum >> 16; + sum = (sum & 0xffff) + to_add; + } + } + + if (tcp_len & 1) { + tcp_len ++; + pad = 1; + } + + for (i=0; i 65535) { + int to_add = sum >> 16; + sum = (sum & 0xffff) + to_add; + } + } + + sum ^= 0xffff; + tcp_header[chksumoffset + 0] = sum >> 8; + tcp_header[chksumoffset + 1] = sum & 0xff; +} + + +/* + * net_ip_icmp(): + * + * Handle an ICMP packet. + * + * The IP header (at offset 14) could look something like + * + * ver=45 tos=00 len=0054 id=001a ofs=0000 ttl=ff p=01 sum=a87e + * src=0a000005 dst=03050607 + * + * and the ICMP specific data (beginning at offset 34): + * + * type=08 code=00 chksum=b8bf + * 000c0008d5cee94089190c0008090a0b + * 0c0d0e0f101112131415161718191a1b + * 1c1d1e1f202122232425262728292a2b + * 2c2d2e2f3031323334353637 + */ +static void net_ip_icmp(struct net *net, struct nic_data *nic, + unsigned char *packet, int len) +{ + int type; + struct ethernet_packet_link *lp; + + type = packet[34]; + + switch (type) { + case 8: /* ECHO request */ + debugmsg(SUBSYS_NET, "ICMP", VERBOSITY_DEBUG, "ECHO request"); + + lp = net_allocate_ethernet_packet_link(net, nic, len); + + /* Copy the old packet first: */ + memcpy(lp->data + 12, packet + 12, len - 12); + + /* Switch to and from ethernet addresses: */ + memcpy(lp->data + 0, packet + 6, 6); + memcpy(lp->data + 6, packet + 0, 6); + + /* Switch to and from IP addresses: */ + memcpy(lp->data + 26, packet + 30, 4); + memcpy(lp->data + 30, packet + 26, 4); + + /* Change from echo REQUEST to echo REPLY: */ + lp->data[34] = 0x00; + + /* Decrease the TTL to a low value: */ + lp->data[22] = 2; + + /* Recalculate ICMP checksum: */ + net_ip_checksum(lp->data + 34, 2, len - 34); + + /* Recalculate IP header checksum: */ + net_ip_checksum(lp->data + 14, 10, 20); + + break; + default: + debugmsg(SUBSYS_NET, "ICMP", VERBOSITY_WARNING, "type %i not yet implemented", type); + } +} + + +/* + * tcp_closeconnection(): + * + * Helper function which closes down a TCP connection completely. + */ +static void tcp_closeconnection(struct net *net, int con_id) +{ + close(net->tcp_connections[con_id].socket); + net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; + net->tcp_connections[con_id].in_use = 0; + net->tcp_connections[con_id].incoming_buf_len = 0; +} + + +/* + * net_ip_tcp_connectionreply(): + * + * When changing from state _TRYINGTOCONNECT to _CONNECTED, then this + * function should be called with connecting set to 1. + * + * To send a generic ack reply, set connecting to 0. + * + * To send data (PSH), set data to non-NULL and datalen to the length. + * + * This creates an ethernet packet for the guest OS with an ACK to the + * initial SYN packet. + */ +void net_ip_tcp_connectionreply(struct net *net, struct nic_data *nic, + int con_id, int connecting, unsigned char *data, int datalen, int rst) +{ + struct ethernet_packet_link *lp; + int tcp_length, ip_len, option_len = 20; + + if (connecting) + net->tcp_connections[con_id].outside_acknr = + net->tcp_connections[con_id].inside_seqnr + 1; + + net->tcp_connections[con_id].tcp_id ++; + tcp_length = 20 + option_len + datalen; + ip_len = 20 + tcp_length; + lp = net_allocate_ethernet_packet_link(net, nic, 14 + ip_len); + + /* Ethernet header: */ + memcpy(lp->data + 0, net->tcp_connections[con_id].ethernet_address, 6); + memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); + lp->data[12] = 0x08; /* IP = 0x0800 */ + lp->data[13] = 0x00; + + /* IP header: */ + lp->data[14] = 0x45; /* ver */ + lp->data[15] = 0x10; /* tos */ + lp->data[16] = ip_len >> 8; + lp->data[17] = ip_len & 0xff; + lp->data[18] = net->tcp_connections[con_id].tcp_id >> 8; + lp->data[19] = net->tcp_connections[con_id].tcp_id & 0xff; + lp->data[20] = 0x40; /* don't fragment */ + lp->data[21] = 0x00; + lp->data[22] = 0x40; /* ttl */ + lp->data[23] = 6; /* p = TCP */ + memcpy(lp->data + 26, net->tcp_connections[con_id]. + outside_ip_address, 4); + memcpy(lp->data + 30, net->tcp_connections[con_id]. + inside_ip_address, 4); + net_ip_checksum(lp->data + 14, 10, 20); + + /* TCP header and options at offset 34: */ + lp->data[34] = net->tcp_connections[con_id].outside_tcp_port >> 8; + lp->data[35] = net->tcp_connections[con_id].outside_tcp_port & 0xff; + lp->data[36] = net->tcp_connections[con_id].inside_tcp_port >> 8; + lp->data[37] = net->tcp_connections[con_id].inside_tcp_port & 0xff; + lp->data[38] = (net->tcp_connections[con_id]. + outside_seqnr >> 24) & 0xff; + lp->data[39] = (net->tcp_connections[con_id]. + outside_seqnr >> 16) & 0xff; + lp->data[40] = (net->tcp_connections[con_id]. + outside_seqnr >> 8) & 0xff; + lp->data[41] = net->tcp_connections[con_id]. + outside_seqnr & 0xff; + lp->data[42] = (net->tcp_connections[con_id]. + outside_acknr >> 24) & 0xff; + lp->data[43] = (net->tcp_connections[con_id]. + outside_acknr >> 16) & 0xff; + lp->data[44] = (net->tcp_connections[con_id]. + outside_acknr >> 8) & 0xff; + lp->data[45] = net->tcp_connections[con_id].outside_acknr & 0xff; + + /* Control */ + lp->data[46] = (option_len + 20) / 4 * 0x10; + lp->data[47] = 0x10; /* ACK */ + if (connecting) + lp->data[47] |= 0x02; /* SYN */ + if (net->tcp_connections[con_id].state == TCP_OUTSIDE_CONNECTED) + lp->data[47] |= 0x08; /* PSH */ + if (rst) + lp->data[47] |= 0x04; /* RST */ + if (net->tcp_connections[con_id].state >= TCP_OUTSIDE_DISCONNECTED) + lp->data[47] |= 0x01; /* FIN */ + + /* Window */ + lp->data[48] = 0x10; + lp->data[49] = 0x00; + + /* no urgent ptr */ + + /* options */ + /* TODO: HAHA, this is ugly */ + lp->data[54] = 0x02; + lp->data[55] = 0x04; + lp->data[56] = 0x05; + lp->data[57] = 0xb4; + lp->data[58] = 0x01; + lp->data[59] = 0x03; + lp->data[60] = 0x03; + lp->data[61] = 0x00; + lp->data[62] = 0x01; + lp->data[63] = 0x01; + lp->data[64] = 0x08; + lp->data[65] = 0x0a; + lp->data[66] = (net->timestamp >> 24) & 0xff; + lp->data[67] = (net->timestamp >> 16) & 0xff; + lp->data[68] = (net->timestamp >> 8) & 0xff; + lp->data[69] = net->timestamp & 0xff; + lp->data[70] = (net->tcp_connections[con_id]. + inside_timestamp >> 24) & 0xff; + lp->data[71] = (net->tcp_connections[con_id]. + inside_timestamp >> 16) & 0xff; + lp->data[72] = (net->tcp_connections[con_id]. + inside_timestamp >> 8) & 0xff; + lp->data[73] = net->tcp_connections[con_id]. + inside_timestamp & 0xff; + + /* data: */ + if (data != NULL) { + memcpy(lp->data + 74, data, datalen); + net->tcp_connections[con_id].outside_seqnr += datalen; + } + + /* Checksum: */ + net_ip_tcp_checksum(lp->data + 34, 16, tcp_length, + lp->data + 26, lp->data + 30, 0); + + if (net_ip_debug) { + fatal("[ net_ip_tcp_connectionreply(%i): ", connecting); + for (int i=0; idata[i]); + fatal(" ]\n"); + } + + if (connecting) + net->tcp_connections[con_id].outside_seqnr ++; +} + + +/* + * net_ip_tcp(): + * + * Handle a TCP packet comming from the emulated OS. + * + * The IP header (at offset 14) could look something like + * + * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798 + * src=0a000001 dst=c1abcdef + * + * TCP header, at offset 34: + * + * srcport=fffe dstport=0015 seqnr=af419a1d acknr=00000000 + * control=a002 window=4000 checksum=fe58 urgent=0000 + * and then "options and padding" and then data. + * (020405b4010303000101080a0000000000000000) + * + * See the following URLs for good descriptions of TCP: + * + * http://www.networksorcery.com/enp/protocol/tcp.htm + * http://www.tcpipguide.com/free/t_TCPIPTransmissionControlProtocolTCP.htm + */ +static void net_ip_tcp(struct net *net, struct nic_data *nic, + unsigned char *packet, int len) +{ + int con_id, free_con_id, i, res; + int srcport, dstport, data_offset, window, checksum, urgptr; + int syn, ack, psh, rst, urg, fin; + uint32_t seqnr, acknr; + struct sockaddr_in remote_ip; + fd_set rfds; + struct timeval tv; + int send_ofs; + + if (net_ip_debug) { + fatal("[ net: TCP: "); + for (i=0; i<26; i++) + fatal("%02x", packet[i]); + fatal(" "); + } + + srcport = (packet[34] << 8) + packet[35]; + dstport = (packet[36] << 8) + packet[37]; + + seqnr = (packet[38] << 24) + (packet[39] << 16) + + (packet[40] << 8) + packet[41]; + acknr = (packet[42] << 24) + (packet[43] << 16) + + (packet[44] << 8) + packet[45]; + + if (net_ip_debug) + fatal("%i.%i.%i.%i:%i -> %i.%i.%i.%i:%i, seqnr=%lli acknr=%lli ", + packet[26], packet[27], packet[28], packet[29], srcport, + packet[30], packet[31], packet[32], packet[33], dstport, + (long long)seqnr, (long long)acknr); + + data_offset = (packet[46] >> 4) * 4 + 34; + /* data_offset is now data offset within packet :-) */ + + urg = packet[47] & 32; + ack = packet[47] & 16; + psh = packet[47] & 8; + rst = packet[47] & 4; + syn = packet[47] & 2; + fin = packet[47] & 1; + window = (packet[48] << 8) + packet[49]; + checksum = (packet[50] << 8) + packet[51]; + urgptr = (packet[52] << 8) + packet[53]; + + if (net_ip_debug) { + fatal(urg? "URG " : ""); + fatal(ack? "ACK " : ""); + fatal(psh? "PSH " : ""); + fatal(rst? "RST " : ""); + fatal(syn? "SYN " : ""); + fatal(fin? "FIN " : ""); + + fatal("window=0x%04x checksum=0x%04x urgptr=0x%04x ", window, checksum, urgptr); + + fatal("options="); + for (i=34+20; itcp_connections[i].in_use) + free_con_id = i; + if (net->tcp_connections[i].in_use && + net->tcp_connections[i].inside_tcp_port == srcport && + net->tcp_connections[i].outside_tcp_port == dstport && + memcmp(net->tcp_connections[i].inside_ip_address, + packet + 26, 4) == 0 && + memcmp(net->tcp_connections[i].outside_ip_address, + packet + 30, 4) == 0) { + con_id = i; + break; + } + } + + /* + * Unknown connection, and not SYN? Then drop the packet. + * TODO: Send back RST? + */ + if (con_id < 0 && !syn) { + debug("[ net: TCP: dropping packet from unknown connection," + " %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i %s%s%s%s%s]\n", + packet[26], packet[27], packet[28], packet[29], srcport, + packet[30], packet[31], packet[32], packet[33], dstport, + fin? "FIN ": "", syn? "SYN ": "", ack? "ACK ": "", + psh? "PSH ": "", rst? "RST ": ""); + return; + } + + /* Known connection, and SYN? Then ignore the packet. */ + if (con_id >= 0 && syn) { + debug("[ net: TCP: ignoring redundant SYN packet from known" + " connection, %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i ]\n", + packet[26], packet[27], packet[28], packet[29], srcport, + packet[30], packet[31], packet[32], packet[33], dstport); + return; + } + + /* + * A new outgoing connection? + */ + if (con_id < 0 && syn) { + debug("[ net: TCP: new outgoing connection, %i.%i.%i.%i:%i" + " -> %i.%i.%i.%i:%i ]\n", + packet[26], packet[27], packet[28], packet[29], srcport, + packet[30], packet[31], packet[32], packet[33], dstport); + + /* Find a free connection id to use: */ + if (free_con_id < 0) { +#if 1 + /* + * TODO: Reuse the oldest one currently in use, or + * just drop the new connection attempt? Drop for now. + */ + fatal("[ TOO MANY TCP CONNECTIONS IN USE! " + "Increase MAX_TCP_CONNECTIONS! ]\n"); + return; +#else + int i; + int64_t oldest = net-> + tcp_connections[0].last_used_timestamp; + free_con_id = 0; + + fatal("[ NO FREE TCP SLOTS, REUSING OLDEST ONE ]\n"); + for (i=0; itcp_connections[i]. + last_used_timestamp < oldest) { + oldest = net->tcp_connections[i]. + last_used_timestamp; + free_con_id = i; + } + tcp_closeconnection(net, free_con_id); +#endif + } + + con_id = free_con_id; + memset(&net->tcp_connections[con_id], 0, + sizeof(struct tcp_connection)); + + memcpy(net->tcp_connections[con_id].ethernet_address, + packet + 6, 6); + memcpy(net->tcp_connections[con_id].inside_ip_address, + packet + 26, 4); + net->tcp_connections[con_id].inside_tcp_port = srcport; + memcpy(net->tcp_connections[con_id].outside_ip_address, + packet + 30, 4); + net->tcp_connections[con_id].outside_tcp_port = dstport; + + net->tcp_connections[con_id].socket = + socket(AF_INET, SOCK_STREAM, 0); + if (net->tcp_connections[con_id].socket < 0) { + fatal("[ net: TCP: socket() returned %i ]\n", + net->tcp_connections[con_id].socket); + return; + } + + debug("[ new tcp outgoing socket=%i ]\n", + net->tcp_connections[con_id].socket); + + net->tcp_connections[con_id].in_use = 1; + + /* Set the socket to non-blocking: */ + res = fcntl(net->tcp_connections[con_id].socket, F_GETFL); + fcntl(net->tcp_connections[con_id].socket, F_SETFL, + res | O_NONBLOCK); + + remote_ip.sin_family = AF_INET; + memcpy((unsigned char *)&remote_ip.sin_addr, + net->tcp_connections[con_id].outside_ip_address, 4); + remote_ip.sin_port = htons( + net->tcp_connections[con_id].outside_tcp_port); + + res = connect(net->tcp_connections[con_id].socket, + (struct sockaddr *)&remote_ip, sizeof(remote_ip)); + + /* connect can return -1, and errno = EINPROGRESS + as we might not have connected right away. */ + + net->tcp_connections[con_id].state = + TCP_OUTSIDE_TRYINGTOCONNECT; + + net->tcp_connections[con_id].outside_acknr = 0; + net->tcp_connections[con_id].outside_seqnr = + ((random() & 0xffff) << 16) + (random() & 0xffff); + } + + if (rst) { + debug("[ 'rst': disconnecting TCP connection %i ]\n", con_id); + net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 1); + tcp_closeconnection(net, con_id); + return; + } + + if (ack && net->tcp_connections[con_id].state + == TCP_OUTSIDE_DISCONNECTED2) { + debug("[ 'ack': guestOS's final termination of TCP " + "connection %i ]\n", con_id); + + /* Send an RST? (TODO, this is wrong...) */ + net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 1); + + /* ... and forget about this connection: */ + tcp_closeconnection(net, con_id); + return; + } + + if (fin && net->tcp_connections[con_id].state + == TCP_OUTSIDE_DISCONNECTED) { + debug("[ 'fin': response to outside's disconnection of " + "TCP connection %i ]\n", con_id); + + /* Send an ACK: */ + net->tcp_connections[con_id].state = TCP_OUTSIDE_CONNECTED; + net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 0); + net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2; + return; + } + + if (fin) { + debug("[ 'fin': guestOS disconnecting TCP connection %i ]\n", + con_id); + + /* Send ACK: */ + net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 0); + net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2; + + /* Return and send FIN: */ + goto ret; + } + + if (ack) { +debug("ACK %i bytes, inside_acknr=%u outside_seqnr=%u\n", + net->tcp_connections[con_id].incoming_buf_len, + net->tcp_connections[con_id].inside_acknr, + net->tcp_connections[con_id].outside_seqnr); + net->tcp_connections[con_id].inside_acknr = acknr; + if (net->tcp_connections[con_id].inside_acknr == + net->tcp_connections[con_id].outside_seqnr && + net->tcp_connections[con_id].incoming_buf_len != 0) { +debug(" all acked\n"); + net->tcp_connections[con_id].incoming_buf_len = 0; + } + } + + net->tcp_connections[con_id].inside_seqnr = seqnr; + + /* TODO: This is hardcoded for a specific NetBSD packet: */ + if (packet[34 + 30] == 0x08 && packet[34 + 31] == 0x0a) + net->tcp_connections[con_id].inside_timestamp = + (packet[34 + 32 + 0] << 24) + + (packet[34 + 32 + 1] << 16) + + (packet[34 + 32 + 2] << 8) + + (packet[34 + 32 + 3] << 0); + + + net->timestamp ++; + net->tcp_connections[con_id].last_used_timestamp = net->timestamp; + + + if (net->tcp_connections[con_id].state != TCP_OUTSIDE_CONNECTED) { + debug("[ not connected to outside ]\n"); + return; + } + + + if (data_offset >= len) + return; + + + /* + * We are here if this is a known connection, and data is to be + * transmitted to the outside world. + */ + + send_ofs = data_offset; + send_ofs += ((int32_t)net->tcp_connections[con_id].outside_acknr + - (int32_t)seqnr); +#if 1 + debug("[ %i bytes of tcp data to be sent, beginning at seqnr %u, ", + len - data_offset, seqnr); + debug("outside is at acknr %u ==> %i actual bytes to be sent ]\n", + net->tcp_connections[con_id].outside_acknr, len - send_ofs); +#endif + + /* Drop outgoing packet if the guest OS' seqnr is not + the same as we have acked. (We have missed something, perhaps.) */ + if (seqnr != net->tcp_connections[con_id].outside_acknr) { + debug("!! outgoing TCP packet dropped (seqnr = %u, " + "outside_acknr = %u)\n", seqnr, + net->tcp_connections[con_id].outside_acknr); + goto ret; + } + + if (len - send_ofs > 0) { + /* Is the socket available for output? */ + FD_ZERO(&rfds); /* write */ + FD_SET(net->tcp_connections[con_id].socket, &rfds); + tv.tv_sec = tv.tv_usec = 0; + errno = 0; + res = select(net->tcp_connections[con_id].socket+1, + NULL, &rfds, NULL, &tv); + if (res < 1) { + net->tcp_connections[con_id].state = + TCP_OUTSIDE_DISCONNECTED; + debug("[ TCP: disconnect on select for writing ]\n"); + goto ret; + } + + res = write(net->tcp_connections[con_id].socket, + packet + send_ofs, len - send_ofs); + + if (res > 0) { + net->tcp_connections[con_id].outside_acknr += res; + } else if (errno == EAGAIN) { + /* Just ignore this attempt. */ + return; + } else { + debug("[ error writing %i bytes to TCP connection %i:" + " errno = %i ]\n", len - send_ofs, con_id, errno); + net->tcp_connections[con_id].state = + TCP_OUTSIDE_DISCONNECTED; + debug("[ TCP: disconnect on write() ]\n"); + goto ret; + } + } + +ret: + /* Send an ACK (or FIN) to the guest OS: */ + net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 0); +} + + +/* + * net_ip_udp(): + * + * Handle a UDP packet. + * + * (See http://www.networksorcery.com/enp/protocol/udp.htm.) + * + * The IP header (at offset 14) could look something like + * + * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798 + * src=0a000001 dst=c1abcdef + * + * and the UDP data (beginning at offset 34): + * + * srcport=fffc dstport=0035 length=0028 chksum=76b6 + * 43e20100000100000000000003667470066e6574627364036f726700001c0001 + */ +static void net_ip_udp(struct net *net, struct nic_data *nic, + unsigned char *packet, int len) +{ + int con_id, free_con_id, i, srcport, dstport, udp_len; + ssize_t res; + struct sockaddr_in remote_ip; + + if ((packet[20] & 0x3f) != 0) { + fatal("[ net_ip_udp(): WARNING! fragmented UDP " + "packet, TODO ]\n"); + return; + } + + srcport = (packet[34] << 8) + packet[35]; + dstport = (packet[36] << 8) + packet[37]; + udp_len = (packet[38] << 8) + packet[39]; + /* chksum at offset 40 and 41 */ + + debug("[ net: UDP: "); + debug("srcport=%i dstport=%i len=%i ", srcport, dstport, udp_len); + for (i=42; i= ' ' && packet[i] < 127) + debug("%c", packet[i]); + else + debug("[%02x]", packet[i]); + } + debug(" ]\n"); + + /* Is this "connection" new, or a currently ongoing one? */ + con_id = free_con_id = -1; + for (i=0; iudp_connections[i].in_use) + free_con_id = i; + if (net->udp_connections[i].in_use && + net->udp_connections[i].inside_udp_port == srcport && + net->udp_connections[i].outside_udp_port == dstport && + memcmp(net->udp_connections[i].inside_ip_address, + packet + 26, 4) == 0 && + memcmp(net->udp_connections[i].outside_ip_address, + packet + 30, 4) == 0) { + con_id = i; + break; + } + } + + debug("&& UDP connection is "); + if (con_id >= 0) + debug("ONGOING"); + else { + debug("NEW"); + if (free_con_id < 0) { + int64_t oldest = net-> + udp_connections[0].last_used_timestamp; + free_con_id = 0; + + debug(", NO FREE SLOTS, REUSING OLDEST ONE"); + for (int j=0; judp_connections[j].last_used_timestamp < oldest) { + oldest = net->udp_connections[j].last_used_timestamp; + free_con_id = j; + } + + close(net->udp_connections[free_con_id].socket); + } + con_id = free_con_id; + memset(&net->udp_connections[con_id], 0, + sizeof(struct udp_connection)); + + memcpy(net->udp_connections[con_id].ethernet_address, + packet + 6, 6); + memcpy(net->udp_connections[con_id].inside_ip_address, + packet + 26, 4); + net->udp_connections[con_id].inside_udp_port = srcport; + memcpy(net->udp_connections[con_id].outside_ip_address, + packet + 30, 4); + net->udp_connections[con_id].outside_udp_port = dstport; + + net->udp_connections[con_id].socket = socket(AF_INET, + SOCK_DGRAM, 0); + if (net->udp_connections[con_id].socket < 0) { + fatal("[ net: UDP: socket() returned %i ]\n", + net->udp_connections[con_id].socket); + return; + } + + debug(" {socket=%i}", net->udp_connections[con_id].socket); + + net->udp_connections[con_id].in_use = 1; + + /* Set the socket to non-blocking: */ + res = fcntl(net->udp_connections[con_id].socket, F_GETFL); + fcntl(net->udp_connections[con_id].socket, F_SETFL, + res | O_NONBLOCK); + } + + debug(", connection id %i\n", con_id); + + net->timestamp ++; + net->udp_connections[con_id].last_used_timestamp = net->timestamp; + + remote_ip.sin_family = AF_INET; + memcpy((unsigned char *)&remote_ip.sin_addr, + net->udp_connections[con_id].outside_ip_address, 4); + + /* + * Special case for the nameserver: If a UDP packet is sent to + * the gateway, it will be forwarded to the nameserver, if it is + * known. + */ + if (net->nameserver_known && + memcmp(net->udp_connections[con_id].outside_ip_address, + &net->gateway_ipv4_addr[0], 4) == 0) { + memcpy((unsigned char *)&remote_ip.sin_addr, + &net->nameserver_ipv4, 4); + net->udp_connections[con_id].fake_ns = 1; + } + + remote_ip.sin_port = htons( + net->udp_connections[con_id].outside_udp_port); + + res = sendto(net->udp_connections[con_id].socket, packet + 42, + len - 42, 0, (const struct sockaddr *)&remote_ip, + sizeof(remote_ip)); + + if (res != len-42) + debug("[ net: UDP: unable to send %i bytes ]\n", len-42); + else + debug("[ net: UDP: OK!!! ]\n"); +} + + +/* + * net_ip(): + * + * Handle an IP packet, coming from the emulated NIC. + */ +void net_ip(struct net *net, struct nic_data *nic, unsigned char *packet, + int len) +{ + int i; + + if (ENOUGH_VERBOSITY(SUBSYS_NET, VERBOSITY_DEBUG)) { + char s[2000]; + + snprintf(s, sizeof(s), "ver=%02x ", packet[14]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "tos=%02x ", packet[15]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "len=%02x%02x ", packet[16], packet[17]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "id=%02x%02x ", packet[18], packet[19]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ofs=%02x%02x ", packet[20], packet[21]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ttl=%02x ", packet[22]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "p=%02x ", packet[23]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "sum=%02x%02x ", packet[24], packet[25]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "src=%02x%02x%02x%02x ", + packet[26], packet[27], packet[28], packet[29]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "dst=%02x%02x%02x%02x ", + packet[30], packet[31], packet[32], packet[33]); + for (i=34; i sizeof(s) - 5) + break; + snprintf(s+strlen(s), sizeof(s)-strlen(s), "%02x", packet[i]); + } + + debugmsg(SUBSYS_NET, "IP", VERBOSITY_DEBUG, "%s", s); + } + + /* Cut off overflowing tail data: */ + if (len > 14 + packet[16]*256 + packet[17]) + len = 14 + packet[16]*256 + packet[17]; + + if (packet[14] == 0x45) { + /* IPv4: */ + switch (packet[23]) { + case 1: /* ICMP */ + net_ip_icmp(net, nic, packet, len); + break; + case 6: /* TCP */ + net_ip_tcp(net, nic, packet, len); + break; + case 17:/* UDP */ + net_ip_udp(net, nic, packet, len); + break; + default:debugmsg(SUBSYS_NET, "IP", VERBOSITY_WARNING, + "UNIMPLEMENTED protocol %i", + packet[23]); + } + } else { + debugmsg(SUBSYS_NET, "IP", VERBOSITY_WARNING, + "UNIMPLEMENTED ip version, first byte = 0x%02x", + packet[14]); + } +} + + +/* + * net_ip_broadcast_dhcp(): + * + * Handle an IPv4 DHCP broadcast packet, coming from the emulated NIC. + * + * Read http://tools.ietf.org/html/rfc2131 for details on DHCP. + * (And http://users.telenet.be/mydotcom/library/network/dhcp.htm.) + */ +static void net_ip_broadcast_dhcp(struct net *net, struct nic_data *nic, + unsigned char *packet, int len) +{ + struct ethernet_packet_link *lp; + int i, reply_len; + + if (ENOUGH_VERBOSITY(SUBSYS_NET, VERBOSITY_DEBUG)) { + char s[4000]; + + snprintf(s, sizeof(s), "ver=%02x ", packet[14]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "tos=%02x ", packet[15]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "len=%02x%02x ", packet[16], packet[17]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "id=%02x%02x ", packet[18], packet[19]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ofs=%02x%02x ", packet[20], packet[21]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ttl=%02x ", packet[22]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "p=%02x ", packet[23]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "sum=%02x%02x ", packet[24], packet[25]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "src=%02x%02x%02x%02x ", + packet[26], packet[27], packet[28], packet[29]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "dst=%02x%02x%02x%02x ", + packet[30], packet[31], packet[32], packet[33]); + for (i=34; i sizeof(s) - 5) + break; + snprintf(s+strlen(s), sizeof(s)-strlen(s), "%02x", packet[i]); + } + + debugmsg(SUBSYS_NET, "IPv4 DHCP", VERBOSITY_DEBUG, "%s", s); + } + + if (len < 34 + 8 + 236) { + debugmsg(SUBSYS_NET, "IPv4 DHCP", VERBOSITY_ERROR, "packet too short? len=%i", len); + return; + } + + /* + * UDP data (at offset 34): + * + * srcport=0044 dstport=0043 length=0134 chksum=a973 + * data = 01010600d116d276000000000000000000000000000000 + * 0000000000102030405060...0000...638253633501...000 + */ + +#if 0 + fatal("op=%02x ", packet[42]); + fatal("htype=%02x ", packet[43]); + fatal("hlen=%02x ", packet[44]); + fatal("hops=%02x ", packet[45]); + fatal("xid=%02x%02x%02x%02x ", packet[46], packet[47], + packet[48], packet[49]); + fatal("secs=%02x%02x ", packet[50], packet[51]); + fatal("flags=%02x%02x ", packet[52], packet[53]); + fatal("ciaddr=%02x%02x%02x%02x ", packet[54], packet[55], + packet[56], packet[57]); + fatal("yiaddr=%02x%02x%02x%02x ", packet[58], packet[59], + packet[60], packet[61]); + fatal("siaddr=%02x%02x%02x%02x ", packet[62], packet[63], + packet[64], packet[65]); + fatal("giaddr=%02x%02x%02x%02x ", packet[66], packet[67], + packet[68], packet[69]); + fatal("chaddr="); + for (i=70; i<70+16; i++) + fatal("%02x", packet[i]); + /* + | sname (64) | + | file (128) | + */ + fatal(" ]\n"); +#endif + + reply_len = 307; + lp = net_allocate_ethernet_packet_link(net, nic, reply_len); + + /* From old packet, copy everything before options field: */ + memcpy(lp->data, packet, 278); + + /* We are sending to the client, from the gateway: */ + memcpy(lp->data + 0, packet + 6, 6); + memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); + + /* Set IP length: */ + lp->data[16] = (reply_len - 14) >> 8; + lp->data[17] = (reply_len - 14) & 0xff; + + /* Set IP addresses: */ + memcpy(lp->data + 26, &net->gateway_ipv4_addr[0], 4); + lp->data[30] = 0xff; + lp->data[31] = 0xff; + lp->data[32] = 0xff; + lp->data[33] = 0xff; + + /* Switch src and dst ports: */ + memcpy(lp->data + 34, packet + 36, 2); + memcpy(lp->data + 36, packet + 34, 2); + + /* Set UDP length: */ + lp->data[38] = (reply_len - 34) >> 8; + lp->data[39] = (reply_len - 34) & 0xff; + + /* Client's (yiaddr) IPv4 address: */ + lp->data[58] = 10; + lp->data[59] = 0; + lp->data[60] = 0; + lp->data[61] = 1; /* TODO */ + + /* Server's IPv4 address: (giaddr) */ + memcpy(lp->data + 66, &net->gateway_ipv4_addr[0], 4); + + /* This is a Reply: */ + lp->data[42] = 0x02; + + snprintf((char *)lp->data + 70+16+64, 8, "gxemul"); + + /* Options field at offset 278: */ + lp->data[278] = 99; + lp->data[279] = 130; + lp->data[280] = 83; + lp->data[281] = 99; + + /* DHCP options, http://tools.ietf.org/html/rfc1533 */ + lp->data[282] = 1; /* subnet mask */ + lp->data[283] = 4; + lp->data[284] = 255; + lp->data[285] = 0; + lp->data[286] = 0; + lp->data[287] = 0; + lp->data[288] = 3; /* router */ + lp->data[289] = 4; + memcpy(lp->data + 290, &net->gateway_ipv4_addr[0], 4); + lp->data[294] = 6; /* domain name server */ + lp->data[295] = 4; + memcpy(lp->data + 296, &net->gateway_ipv4_addr[0], 4); + lp->data[300] = 54; /* server identifier */ + lp->data[301] = 4; + memcpy(lp->data + 302, &net->gateway_ipv4_addr[0], 4); + lp->data[306] = 255; /* end */ + + /* Recalculate IP header checksum: */ + net_ip_checksum(lp->data + 14, 10, 20); + + /* ... and the UDP checksum: */ + net_ip_tcp_checksum(lp->data + 34, 6, reply_len - 34, + lp->data + 26, lp->data + 30, 1); + + if (ENOUGH_VERBOSITY(SUBSYS_NET, VERBOSITY_DEBUG)) { + char s[4000]; + s[0] = '\0'; + + packet = lp->data; + + for (i=0; i<14; i++) { + if (strlen(s) > sizeof(s) - 5) + break; + snprintf(s+strlen(s), sizeof(s)-strlen(s), "%02x", packet[i]); + } + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ver=%02x ", packet[14]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "tos=%02x ", packet[15]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "len=%02x%02x ", packet[16], packet[17]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "id=%02x%02x ", packet[18], packet[19]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ofs=%02x%02x ", packet[20], packet[21]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ttl=%02x ", packet[22]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "p=%02x ", packet[23]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "sum=%02x%02x ", packet[24], packet[25]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "src=%02x%02x%02x%02x ", + packet[26], packet[27], packet[28], packet[29]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "dst=%02x%02x%02x%02x ", + packet[30], packet[31], packet[32], packet[33]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "op=%02x ", packet[42]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "htype=%02x ", packet[43]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "hlen=%02x ", packet[44]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "hops=%02x ", packet[45]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "xid=%02x%02x%02x%02x ", + packet[46], packet[47], packet[48], packet[49]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "secs=%02x%02x ", packet[50], packet[51]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "flags=%02x%02x ", packet[52], packet[53]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ciaddr=%02x%02x%02x%02x ", + packet[54], packet[55], packet[56], packet[57]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "yiaddr=%02x%02x%02x%02x ", + packet[58], packet[59], packet[60], packet[61]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "siaddr=%02x%02x%02x%02x ", + packet[62], packet[63], packet[64], packet[65]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "giaddr=%02x%02x%02x%02x ", + packet[66], packet[67], packet[68], packet[69]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "chaddr="); + for (i=70; i<70+16; i++) { + if (strlen(s) > sizeof(s) - 5) + break; + + snprintf(s+strlen(s), sizeof(s)-strlen(s), "%02x", packet[i]); + } + + debugmsg(SUBSYS_NET, "IPv4 DHCP REPLY", VERBOSITY_DEBUG, "%s", s); + } +} + + +/* + * net_ip_broadcast(): + * + * Handle an IP broadcast packet, coming from the emulated NIC. + * (This is usually a DHCP request, or similar.) + */ +void net_ip_broadcast(struct net *net, struct nic_data *nic, + unsigned char *packet, int len) +{ + unsigned char *p = (unsigned char *) &net->netmask_ipv4; + uint32_t x, y; + int i, xl, warning = 0, match = 0; + + if (ENOUGH_VERBOSITY(SUBSYS_NET, VERBOSITY_DEBUG)) { + char s[4000]; + + snprintf(s, sizeof(s), "ver=%02x ", packet[14]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "tos=%02x ", packet[15]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "len=%02x%02x ", packet[16], packet[17]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "id=%02x%02x ", packet[18], packet[19]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ofs=%02x%02x ", packet[20], packet[21]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ttl=%02x ", packet[22]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "p=%02x ", packet[23]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "sum=%02x%02x ", packet[24], packet[25]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "src=%02x%02x%02x%02x ", + packet[26], packet[27], packet[28], packet[29]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "dst=%02x%02x%02x%02x ", + packet[30], packet[31], packet[32], packet[33]); + for (i=34; i sizeof(s) - 5) + break; + snprintf(s+strlen(s), sizeof(s)-strlen(s), "%02x", packet[i]); + } + + debugmsg(SUBSYS_NET, "ip BROADCAST", VERBOSITY_DEBUG, "%s", s); + } + + /* Check for 10.0.0.255 first, maybe some guest OSes think that + it's a /24 network, regardless of what it actually is. */ + y = (packet[30] << 24) + (packet[31] << 16) + + (packet[32] << 8) + packet[33]; + + x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; + /* Example: x = 10.0.0.0 */ + x |= 255; + + if (x == y) { + warning = 1; + match = 1; + } + + xl = 32 - net->netmask_ipv4_len; + x |= (1 << xl) - 1; + /* x = 10.255.255.255 */ + + if (x == y) + match = 1; + if (y == 0xffffffff) + match = 1; + + if (warning) + fatal("[ net_ip_broadcast(): warning: broadcast to " + "0x%08x, expecting broadcast to 0x%08x or " + "0xffffffff ]\n", y, x); + + /* Cut off overflowing tail data: */ + if (len > 14 + packet[16]*256 + packet[17]) + len = 14 + packet[16]*256 + packet[17]; + + /* Check for known packets: */ + if (packet[14] == 0x45 && /* IPv4 */ + packet[23] == 0x11 && /* UDP */ + packet[34] == 0 && packet[35] == 68 && /* DHCP client */ + packet[36] == 0 && packet[37] == 67) { /* DHCP server */ + net_ip_broadcast_dhcp(net, nic, packet, len); + return; + } + + /* NetBSD seems to send this during shutdown: */ + if (packet[14] == 0x45 && /* IPv4 */ + packet[23] == 0x11 && /* UDP */ + packet[34] == 0xff && packet[35] == 0xff && /* 0xffff */ + packet[36] == 0x00 && packet[37] == 0x6f) { /* ipx-in-ip */ + // Let's ignore for now. + return; + } + + /* Unknown packet: */ + if (ENOUGH_VERBOSITY(SUBSYS_NET, VERBOSITY_ERROR)) { + char s[4000]; + + snprintf(s, sizeof(s), "ver=%02x ", packet[14]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "tos=%02x ", packet[15]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "len=%02x%02x ", packet[16], packet[17]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "id=%02x%02x ", packet[18], packet[19]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ofs=%02x%02x ", packet[20], packet[21]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "ttl=%02x ", packet[22]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "p=%02x ", packet[23]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "sum=%02x%02x ", packet[24], packet[25]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "src=%02x%02x%02x%02x ", + packet[26], packet[27], packet[28], packet[29]); + snprintf(s+strlen(s), sizeof(s)-strlen(s), "dst=%02x%02x%02x%02x ", + packet[30], packet[31], packet[32], packet[33]); + for (i=34; i sizeof(s) - 50) + break; + snprintf(s+strlen(s), sizeof(s)-strlen(s), "%02x", packet[i]); + } + snprintf(s+strlen(s), sizeof(s)-strlen(s), " (match=%i)", match); + + debugmsg(SUBSYS_NET, "ip UNIMPLEMENTED BROADCAST", VERBOSITY_ERROR, "%s", s); + } +} + + +/* + * net_udp_rx_avail(): + * + * Receive any available UDP packets (from the outside world). + */ +void net_udp_rx_avail(struct net *net, struct nic_data *nic) +{ + int received_packets_this_tick = 0; + int max_packets_this_tick = 200; + int con_id; + + for (con_id=0; con_id max_packets_this_tick) + break; + + if (!net->udp_connections[con_id].in_use) + continue; + + if (net->udp_connections[con_id].socket < 0) { + fatal("INTERNAL ERROR in net.c, udp socket < 0 " + "but in use?\n"); + continue; + } + + res = recvfrom(net->udp_connections[con_id].socket, buf, + sizeof(buf), 0, (struct sockaddr *)&from, &from_len); + + /* No more incoming UDP on this connection? */ + if (res < 0) + continue; + + net->timestamp ++; + net->udp_connections[con_id].last_used_timestamp = + net->timestamp; + + net->udp_connections[con_id].udp_id ++; + + /* + * Special case for the nameserver: If a UDP packet is + * received from the nameserver (if the nameserver's IP is + * known), fake it so that it comes from the gateway instead. + */ + if (net->udp_connections[con_id].fake_ns) + memcpy(((unsigned char *)(&from))+4, + &net->gateway_ipv4_addr[0], 4); + + /* + * We now have a UDP packet of size 'res' which we need + * turn into one or more ethernet packets for the emulated + * operating system. Ethernet packets are at most 1518 + * bytes long. With some margin, that means we can have + * about 1500 bytes per packet. + * + * Ethernet = 14 bytes + * IP = 20 bytes + * (UDP = 8 bytes + data) + * + * So data can be at most max_per_packet - 34. For UDP + * fragments, each multiple should (?) be a multiple of + * 8 bytes, except the last which doesn't have any such + * restriction. + */ + max_per_packet = 1500; + + /* UDP: */ + udp_len = res + 8; + /* from[2..3] = outside_udp_port */ + udp_data[0] = ((unsigned char *)&from)[2]; + udp_data[1] = ((unsigned char *)&from)[3]; + udp_data[2] = (net->udp_connections[con_id]. + inside_udp_port >> 8) & 0xff; + udp_data[3] = net->udp_connections[con_id]. + inside_udp_port & 0xff; + udp_data[4] = udp_len >> 8; + udp_data[5] = udp_len & 0xff; + udp_data[6] = 0; + udp_data[7] = 0; + memcpy(udp_data + 8, buf, res); + /* + * TODO: UDP checksum, if necessary. At least NetBSD + * and OpenBSD accept UDP packets with 0x0000 in the + * checksum field anyway. + */ + + while (bytes_converted < udp_len) { + this_packets_data_length = udp_len - bytes_converted; + + /* Do we need to fragment? */ + if (this_packets_data_length > max_per_packet-34) { + this_packets_data_length = + max_per_packet - 34; + while (this_packets_data_length & 7) + this_packets_data_length --; + } + + ip_len = 20 + this_packets_data_length; + + lp = net_allocate_ethernet_packet_link(net, nic, + 14 + 20 + this_packets_data_length); + + /* Ethernet header: */ + memcpy(lp->data + 0, net->udp_connections[con_id]. + ethernet_address, 6); + memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); + lp->data[12] = 0x08; /* IP = 0x0800 */ + lp->data[13] = 0x00; + + /* IP header: */ + lp->data[14] = 0x45; /* ver */ + lp->data[15] = 0x00; /* tos */ + lp->data[16] = ip_len >> 8; + lp->data[17] = ip_len & 0xff; + lp->data[18] = net->udp_connections[con_id].udp_id >> 8; + lp->data[19] = net->udp_connections[con_id].udp_id + & 0xff; + lp->data[20] = (fragment_ofs >> 8); + if (bytes_converted + this_packets_data_length + < udp_len) + lp->data[20] |= 0x20; /* More fragments */ + lp->data[21] = fragment_ofs & 0xff; + lp->data[22] = 0x40; /* ttl */ + lp->data[23] = 17; /* p = UDP */ + lp->data[26] = ((unsigned char *)&from)[4]; + lp->data[27] = ((unsigned char *)&from)[5]; + lp->data[28] = ((unsigned char *)&from)[6]; + lp->data[29] = ((unsigned char *)&from)[7]; + memcpy(lp->data + 30, net->udp_connections[con_id]. + inside_ip_address, 4); + net_ip_checksum(lp->data + 14, 10, 20); + + memcpy(lp->data+34, udp_data + bytes_converted, + this_packets_data_length); + + bytes_converted += this_packets_data_length; + fragment_ofs = bytes_converted / 8; + + received_packets_this_tick ++; + } + + /* This makes sure we check this connection AGAIN + for more incoming UDP packets, before moving to the + next connection: */ + con_id --; + } +} + + +/* + * net_tcp_rx_avail(): + * + * Receive any available TCP packets (from the outside world). + */ +void net_tcp_rx_avail(struct net *net, struct nic_data *nic) +{ + int received_packets_this_tick = 0; + int max_packets_this_tick = 200; + int con_id; + + for (con_id=0; con_id max_packets_this_tick) + break; + + if (!net->tcp_connections[con_id].in_use) + continue; + + if (net->tcp_connections[con_id].socket < 0) { + fatal("INTERNAL ERROR in net.c, tcp socket < 0" + " but in use?\n"); + continue; + } + + if (net->tcp_connections[con_id].incoming_buf == NULL) + CHECK_ALLOCATION(net->tcp_connections[con_id]. + incoming_buf = (unsigned char *) malloc(TCP_INCOMING_BUF_LEN)); + + if (net->tcp_connections[con_id].state >= + TCP_OUTSIDE_DISCONNECTED) + continue; + + /* Is the socket available for output? */ + FD_ZERO(&rfds); /* write */ + FD_SET(net->tcp_connections[con_id].socket, &rfds); + tv.tv_sec = tv.tv_usec = 0; + errno = 0; + res = select(net->tcp_connections[con_id].socket+1, + NULL, &rfds, NULL, &tv); + + if (errno == ECONNREFUSED) { + fatal("[ ECONNREFUSED: TODO ]\n"); + net->tcp_connections[con_id].state = + TCP_OUTSIDE_DISCONNECTED; + fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED " + "(refused connection)\n"); + continue; + } + + if (errno == ETIMEDOUT) { + fatal("[ ETIMEDOUT: TODO ]\n"); + /* TODO */ + net->tcp_connections[con_id].state = + TCP_OUTSIDE_DISCONNECTED; + fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED " + "(timeout)\n"); + continue; + } + + if (net->tcp_connections[con_id].state == + TCP_OUTSIDE_TRYINGTOCONNECT && res > 0) { + net->tcp_connections[con_id].state = + TCP_OUTSIDE_CONNECTED; + debug("CHANGING TO TCP_OUTSIDE_CONNECTED\n"); + net_ip_tcp_connectionreply(net, nic, con_id, 1, + NULL, 0, 0); + } + + if (net->tcp_connections[con_id].state == + TCP_OUTSIDE_CONNECTED && res < 1) { + continue; + } + + /* + * Does this connection have unacknowledged data? Then, if + * enough number of rounds have passed, try to resend it using + * the old value of seqnr. + */ + if (net->tcp_connections[con_id].incoming_buf_len != 0) { + net->tcp_connections[con_id].incoming_buf_rounds ++; + if (net->tcp_connections[con_id].incoming_buf_rounds > + 10000) { + debug(" at seqnr %u but backing back to %u," + " resending %i bytes\n", + net->tcp_connections[con_id].outside_seqnr, + net->tcp_connections[con_id]. + incoming_buf_seqnr, + net->tcp_connections[con_id]. + incoming_buf_len); + + net->tcp_connections[con_id]. + incoming_buf_rounds = 0; + net->tcp_connections[con_id].outside_seqnr = + net->tcp_connections[con_id]. + incoming_buf_seqnr; + + net_ip_tcp_connectionreply(net, nic, con_id, + 0, net->tcp_connections[con_id]. + incoming_buf, + net->tcp_connections[con_id]. + incoming_buf_len, 0); + } + continue; + } + + /* Don't receive unless the guest OS is ready! */ + if (((int32_t)net->tcp_connections[con_id].outside_seqnr - + (int32_t)net->tcp_connections[con_id].inside_acknr) > 0) { +/* fatal("YOYO 1! outside_seqnr - inside_acknr = %i\n", + net->tcp_connections[con_id].outside_seqnr - + net->tcp_connections[con_id].inside_acknr); */ + continue; + } + + /* Is there incoming data available on the socket? */ + FD_ZERO(&rfds); /* read */ + FD_SET(net->tcp_connections[con_id].socket, &rfds); + tv.tv_sec = tv.tv_usec = 0; + res2 = select(net->tcp_connections[con_id].socket+1, &rfds, + NULL, NULL, &tv); + + /* No more incoming TCP data on this connection? */ + if (res2 < 1) + continue; + + res = read(net->tcp_connections[con_id].socket, buf, 1400); + if (res > 0) { + /* debug("\n -{- %lli -}-\n", (long long)res); */ + net->tcp_connections[con_id].incoming_buf_len = res; + net->tcp_connections[con_id].incoming_buf_rounds = 0; + net->tcp_connections[con_id].incoming_buf_seqnr = + net->tcp_connections[con_id].outside_seqnr; + debug(" putting %i bytes (seqnr %u) in the incoming " + "buf\n", res, net->tcp_connections[con_id]. + incoming_buf_seqnr); + memcpy(net->tcp_connections[con_id].incoming_buf, + buf, res); + + net_ip_tcp_connectionreply(net, nic, con_id, 0, + buf, res, 0); + } else if (res == 0) { + net->tcp_connections[con_id].state = + TCP_OUTSIDE_DISCONNECTED; + debug("CHANGING TO TCP_OUTSIDE_DISCONNECTED, read" + " res=0\n"); + net_ip_tcp_connectionreply(net, nic, con_id, 0, + NULL, 0, 0); + } else { + net->tcp_connections[con_id].state = + TCP_OUTSIDE_DISCONNECTED; + fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED, " + "read res<=0, errno = %i\n", errno); + net_ip_tcp_connectionreply(net, nic, con_id, 0, + NULL, 0, 0); + } + + net->timestamp ++; + net->tcp_connections[con_id].last_used_timestamp = + net->timestamp; + } +} + + diff -Nru gxemul-0.6.2/src/net/net_ip.cc gxemul-0.7.0+dfsg/src/net/net_ip.cc --- gxemul-0.6.2/src/net/net_ip.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net_ip.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,1546 +0,0 @@ -/* - * Copyright (C) 2004-2010 Anders Gavare. 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. The name of the author 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. - * - * - * Internet Protocol related networking stuff. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "misc.h" -#include "net.h" - - -/* #define debug fatal */ - - -/* - * net_ip_checksum(): - * - * Fill in an IP header checksum. (This works for ICMP too.) - * chksumoffset should be 10 for IP headers, and len = 20. - * For ICMP packets, chksumoffset = 2 and len = length of the ICMP packet. - */ -void net_ip_checksum(unsigned char *ip_header, int chksumoffset, int len) -{ - int i; - uint32_t sum = 0; - - for (i=0; i 65535) { - int to_add = sum >> 16; - sum = (sum & 0xffff) + to_add; - } - } - - sum ^= 0xffff; - ip_header[chksumoffset + 0] = sum >> 8; - ip_header[chksumoffset + 1] = sum & 0xff; -} - - -/* - * net_ip_tcp_checksum(): - * - * Fill in a TCP header checksum. This differs slightly from the IP - * checksum. The checksum is calculated on a pseudo header, the actual - * TCP header, and the data. This is what the pseudo header looks like: - * - * uint32_t srcaddr; - * uint32_t dstaddr; - * uint16_t protocol; (= 6 for tcp) - * uint16_t tcp_len; - * - * tcp_len is length of header PLUS data. The psedo header is created - * internally here, and does not need to be supplied by the caller. - */ -void net_ip_tcp_checksum(unsigned char *tcp_header, int chksumoffset, - int tcp_len, unsigned char *srcaddr, unsigned char *dstaddr, - int udpflag) -{ - int i, pad = 0; - unsigned char pseudoh[12]; - uint32_t sum = 0; - - memcpy(pseudoh + 0, srcaddr, 4); - memcpy(pseudoh + 4, dstaddr, 4); - pseudoh[8] = 0x00; - pseudoh[9] = udpflag? 17 : 6; - pseudoh[10] = tcp_len >> 8; - pseudoh[11] = tcp_len & 255; - - for (i=0; i<12; i+=2) { - uint16_t w = (pseudoh[i] << 8) + pseudoh[i+1]; - sum += w; - while (sum > 65535) { - int to_add = sum >> 16; - sum = (sum & 0xffff) + to_add; - } - } - - if (tcp_len & 1) { - tcp_len ++; - pad = 1; - } - - for (i=0; i 65535) { - int to_add = sum >> 16; - sum = (sum & 0xffff) + to_add; - } - } - - sum ^= 0xffff; - tcp_header[chksumoffset + 0] = sum >> 8; - tcp_header[chksumoffset + 1] = sum & 0xff; -} - - -/* - * net_ip_icmp(): - * - * Handle an ICMP packet. - * - * The IP header (at offset 14) could look something like - * - * ver=45 tos=00 len=0054 id=001a ofs=0000 ttl=ff p=01 sum=a87e - * src=0a000005 dst=03050607 - * - * and the ICMP specific data (beginning at offset 34): - * - * type=08 code=00 chksum=b8bf - * 000c0008d5cee94089190c0008090a0b - * 0c0d0e0f101112131415161718191a1b - * 1c1d1e1f202122232425262728292a2b - * 2c2d2e2f3031323334353637 - */ -static void net_ip_icmp(struct net *net, void *extra, - unsigned char *packet, int len) -{ - int type; - struct ethernet_packet_link *lp; - - type = packet[34]; - - switch (type) { - case 8: /* ECHO request */ - debug("[ ICMP echo ]\n"); - lp = net_allocate_ethernet_packet_link(net, extra, len); - - /* Copy the old packet first: */ - memcpy(lp->data + 12, packet + 12, len - 12); - - /* Switch to and from ethernet addresses: */ - memcpy(lp->data + 0, packet + 6, 6); - memcpy(lp->data + 6, packet + 0, 6); - - /* Switch to and from IP addresses: */ - memcpy(lp->data + 26, packet + 30, 4); - memcpy(lp->data + 30, packet + 26, 4); - - /* Change from echo REQUEST to echo REPLY: */ - lp->data[34] = 0x00; - - /* Decrease the TTL to a low value: */ - lp->data[22] = 2; - - /* Recalculate ICMP checksum: */ - net_ip_checksum(lp->data + 34, 2, len - 34); - - /* Recalculate IP header checksum: */ - net_ip_checksum(lp->data + 14, 10, 20); - - break; - default: - fatal("[ net: ICMP type %i not yet implemented ]\n", type); - } -} - - -/* - * tcp_closeconnection(): - * - * Helper function which closes down a TCP connection completely. - */ -static void tcp_closeconnection(struct net *net, int con_id) -{ - close(net->tcp_connections[con_id].socket); - net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED; - net->tcp_connections[con_id].in_use = 0; - net->tcp_connections[con_id].incoming_buf_len = 0; -} - - -/* - * net_ip_tcp_connectionreply(): - * - * When changing from state _TRYINGTOCONNECT to _CONNECTED, then this - * function should be called with connecting set to 1. - * - * To send a generic ack reply, set connecting to 0. - * - * To send data (PSH), set data to non-NULL and datalen to the length. - * - * This creates an ethernet packet for the guest OS with an ACK to the - * initial SYN packet. - */ -void net_ip_tcp_connectionreply(struct net *net, void *extra, - int con_id, int connecting, unsigned char *data, int datalen, int rst) -{ - struct ethernet_packet_link *lp; - int tcp_length, ip_len, option_len = 20; - - if (connecting) - net->tcp_connections[con_id].outside_acknr = - net->tcp_connections[con_id].inside_seqnr + 1; - - net->tcp_connections[con_id].tcp_id ++; - tcp_length = 20 + option_len + datalen; - ip_len = 20 + tcp_length; - lp = net_allocate_ethernet_packet_link(net, extra, 14 + ip_len); - - /* Ethernet header: */ - memcpy(lp->data + 0, net->tcp_connections[con_id].ethernet_address, 6); - memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); - lp->data[12] = 0x08; /* IP = 0x0800 */ - lp->data[13] = 0x00; - - /* IP header: */ - lp->data[14] = 0x45; /* ver */ - lp->data[15] = 0x10; /* tos */ - lp->data[16] = ip_len >> 8; - lp->data[17] = ip_len & 0xff; - lp->data[18] = net->tcp_connections[con_id].tcp_id >> 8; - lp->data[19] = net->tcp_connections[con_id].tcp_id & 0xff; - lp->data[20] = 0x40; /* don't fragment */ - lp->data[21] = 0x00; - lp->data[22] = 0x40; /* ttl */ - lp->data[23] = 6; /* p = TCP */ - memcpy(lp->data + 26, net->tcp_connections[con_id]. - outside_ip_address, 4); - memcpy(lp->data + 30, net->tcp_connections[con_id]. - inside_ip_address, 4); - net_ip_checksum(lp->data + 14, 10, 20); - - /* TCP header and options at offset 34: */ - lp->data[34] = net->tcp_connections[con_id].outside_tcp_port >> 8; - lp->data[35] = net->tcp_connections[con_id].outside_tcp_port & 0xff; - lp->data[36] = net->tcp_connections[con_id].inside_tcp_port >> 8; - lp->data[37] = net->tcp_connections[con_id].inside_tcp_port & 0xff; - lp->data[38] = (net->tcp_connections[con_id]. - outside_seqnr >> 24) & 0xff; - lp->data[39] = (net->tcp_connections[con_id]. - outside_seqnr >> 16) & 0xff; - lp->data[40] = (net->tcp_connections[con_id]. - outside_seqnr >> 8) & 0xff; - lp->data[41] = net->tcp_connections[con_id]. - outside_seqnr & 0xff; - lp->data[42] = (net->tcp_connections[con_id]. - outside_acknr >> 24) & 0xff; - lp->data[43] = (net->tcp_connections[con_id]. - outside_acknr >> 16) & 0xff; - lp->data[44] = (net->tcp_connections[con_id]. - outside_acknr >> 8) & 0xff; - lp->data[45] = net->tcp_connections[con_id].outside_acknr & 0xff; - - /* Control */ - lp->data[46] = (option_len + 20) / 4 * 0x10; - lp->data[47] = 0x10; /* ACK */ - if (connecting) - lp->data[47] |= 0x02; /* SYN */ - if (net->tcp_connections[con_id].state == TCP_OUTSIDE_CONNECTED) - lp->data[47] |= 0x08; /* PSH */ - if (rst) - lp->data[47] |= 0x04; /* RST */ - if (net->tcp_connections[con_id].state >= TCP_OUTSIDE_DISCONNECTED) - lp->data[47] |= 0x01; /* FIN */ - - /* Window */ - lp->data[48] = 0x10; - lp->data[49] = 0x00; - - /* no urgent ptr */ - - /* options */ - /* TODO: HAHA, this is ugly */ - lp->data[54] = 0x02; - lp->data[55] = 0x04; - lp->data[56] = 0x05; - lp->data[57] = 0xb4; - lp->data[58] = 0x01; - lp->data[59] = 0x03; - lp->data[60] = 0x03; - lp->data[61] = 0x00; - lp->data[62] = 0x01; - lp->data[63] = 0x01; - lp->data[64] = 0x08; - lp->data[65] = 0x0a; - lp->data[66] = (net->timestamp >> 24) & 0xff; - lp->data[67] = (net->timestamp >> 16) & 0xff; - lp->data[68] = (net->timestamp >> 8) & 0xff; - lp->data[69] = net->timestamp & 0xff; - lp->data[70] = (net->tcp_connections[con_id]. - inside_timestamp >> 24) & 0xff; - lp->data[71] = (net->tcp_connections[con_id]. - inside_timestamp >> 16) & 0xff; - lp->data[72] = (net->tcp_connections[con_id]. - inside_timestamp >> 8) & 0xff; - lp->data[73] = net->tcp_connections[con_id]. - inside_timestamp & 0xff; - - /* data: */ - if (data != NULL) { - memcpy(lp->data + 74, data, datalen); - net->tcp_connections[con_id].outside_seqnr += datalen; - } - - /* Checksum: */ - net_ip_tcp_checksum(lp->data + 34, 16, tcp_length, - lp->data + 26, lp->data + 30, 0); - -#if 0 - { - int i; - fatal("[ net_ip_tcp_connectionreply(%i): ", connecting); - for (i=0; idata[i]); - fatal(" ]\n"); - } -#endif - - if (connecting) - net->tcp_connections[con_id].outside_seqnr ++; -} - - -/* - * net_ip_tcp(): - * - * Handle a TCP packet comming from the emulated OS. - * - * The IP header (at offset 14) could look something like - * - * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798 - * src=0a000001 dst=c1abcdef - * - * TCP header, at offset 34: - * - * srcport=fffe dstport=0015 seqnr=af419a1d acknr=00000000 - * control=a002 window=4000 checksum=fe58 urgent=0000 - * and then "options and padding" and then data. - * (020405b4010303000101080a0000000000000000) - * - * See the following URLs for good descriptions of TCP: - * - * http://www.networksorcery.com/enp/protocol/tcp.htm - * http://www.tcpipguide.com/free/t_TCPIPTransmissionControlProtocolTCP.htm - */ -static void net_ip_tcp(struct net *net, void *extra, - unsigned char *packet, int len) -{ - int con_id, free_con_id, i, res; - int srcport, dstport, data_offset, window, checksum, urgptr; - int syn, ack, psh, rst, urg, fin; - uint32_t seqnr, acknr; - struct sockaddr_in remote_ip; - fd_set rfds; - struct timeval tv; - int send_ofs; - -#if 0 - fatal("[ net: TCP: "); - for (i=0; i<26; i++) - fatal("%02x", packet[i]); - fatal(" "); -#endif - - srcport = (packet[34] << 8) + packet[35]; - dstport = (packet[36] << 8) + packet[37]; - - seqnr = (packet[38] << 24) + (packet[39] << 16) - + (packet[40] << 8) + packet[41]; - acknr = (packet[42] << 24) + (packet[43] << 16) - + (packet[44] << 8) + packet[45]; - -#if 0 - fatal("%i.%i.%i.%i:%i -> %i.%i.%i.%i:%i, seqnr=%lli acknr=%lli ", - packet[26], packet[27], packet[28], packet[29], srcport, - packet[30], packet[31], packet[32], packet[33], dstport, - (long long)seqnr, (long long)acknr); -#endif - - data_offset = (packet[46] >> 4) * 4 + 34; - /* data_offset is now data offset within packet :-) */ - - urg = packet[47] & 32; - ack = packet[47] & 16; - psh = packet[47] & 8; - rst = packet[47] & 4; - syn = packet[47] & 2; - fin = packet[47] & 1; - window = (packet[48] << 8) + packet[49]; - checksum = (packet[50] << 8) + packet[51]; - urgptr = (packet[52] << 8) + packet[53]; - -#if 0 - fatal(urg? "URG " : ""); - fatal(ack? "ACK " : ""); - fatal(psh? "PSH " : ""); - fatal(rst? "RST " : ""); - fatal(syn? "SYN " : ""); - fatal(fin? "FIN " : ""); - - fatal("window=0x%04x checksum=0x%04x urgptr=0x%04x ", - window, checksum, urgptr); - - fatal("options="); - for (i=34+20; itcp_connections[i].in_use) - free_con_id = i; - if (net->tcp_connections[i].in_use && - net->tcp_connections[i].inside_tcp_port == srcport && - net->tcp_connections[i].outside_tcp_port == dstport && - memcmp(net->tcp_connections[i].inside_ip_address, - packet + 26, 4) == 0 && - memcmp(net->tcp_connections[i].outside_ip_address, - packet + 30, 4) == 0) { - con_id = i; - break; - } - } - - /* - * Unknown connection, and not SYN? Then drop the packet. - * TODO: Send back RST? - */ - if (con_id < 0 && !syn) { - debug("[ net: TCP: dropping packet from unknown connection," - " %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i %s%s%s%s%s]\n", - packet[26], packet[27], packet[28], packet[29], srcport, - packet[30], packet[31], packet[32], packet[33], dstport, - fin? "FIN ": "", syn? "SYN ": "", ack? "ACK ": "", - psh? "PSH ": "", rst? "RST ": ""); - return; - } - - /* Known connection, and SYN? Then ignore the packet. */ - if (con_id >= 0 && syn) { - debug("[ net: TCP: ignoring redundant SYN packet from known" - " connection, %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i ]\n", - packet[26], packet[27], packet[28], packet[29], srcport, - packet[30], packet[31], packet[32], packet[33], dstport); - return; - } - - /* - * A new outgoing connection? - */ - if (con_id < 0 && syn) { - debug("[ net: TCP: new outgoing connection, %i.%i.%i.%i:%i" - " -> %i.%i.%i.%i:%i ]\n", - packet[26], packet[27], packet[28], packet[29], srcport, - packet[30], packet[31], packet[32], packet[33], dstport); - - /* Find a free connection id to use: */ - if (free_con_id < 0) { -#if 1 - /* - * TODO: Reuse the oldest one currently in use, or - * just drop the new connection attempt? Drop for now. - */ - fatal("[ TOO MANY TCP CONNECTIONS IN USE! " - "Increase MAX_TCP_CONNECTIONS! ]\n"); - return; -#else - int i; - int64_t oldest = net-> - tcp_connections[0].last_used_timestamp; - free_con_id = 0; - - fatal("[ NO FREE TCP SLOTS, REUSING OLDEST ONE ]\n"); - for (i=0; itcp_connections[i]. - last_used_timestamp < oldest) { - oldest = net->tcp_connections[i]. - last_used_timestamp; - free_con_id = i; - } - tcp_closeconnection(net, free_con_id); -#endif - } - - con_id = free_con_id; - memset(&net->tcp_connections[con_id], 0, - sizeof(struct tcp_connection)); - - memcpy(net->tcp_connections[con_id].ethernet_address, - packet + 6, 6); - memcpy(net->tcp_connections[con_id].inside_ip_address, - packet + 26, 4); - net->tcp_connections[con_id].inside_tcp_port = srcport; - memcpy(net->tcp_connections[con_id].outside_ip_address, - packet + 30, 4); - net->tcp_connections[con_id].outside_tcp_port = dstport; - - net->tcp_connections[con_id].socket = - socket(AF_INET, SOCK_STREAM, 0); - if (net->tcp_connections[con_id].socket < 0) { - fatal("[ net: TCP: socket() returned %i ]\n", - net->tcp_connections[con_id].socket); - return; - } - - debug("[ new tcp outgoing socket=%i ]\n", - net->tcp_connections[con_id].socket); - - net->tcp_connections[con_id].in_use = 1; - - /* Set the socket to non-blocking: */ - res = fcntl(net->tcp_connections[con_id].socket, F_GETFL); - fcntl(net->tcp_connections[con_id].socket, F_SETFL, - res | O_NONBLOCK); - - remote_ip.sin_family = AF_INET; - memcpy((unsigned char *)&remote_ip.sin_addr, - net->tcp_connections[con_id].outside_ip_address, 4); - remote_ip.sin_port = htons( - net->tcp_connections[con_id].outside_tcp_port); - - res = connect(net->tcp_connections[con_id].socket, - (struct sockaddr *)&remote_ip, sizeof(remote_ip)); - - /* connect can return -1, and errno = EINPROGRESS - as we might not have connected right away. */ - - net->tcp_connections[con_id].state = - TCP_OUTSIDE_TRYINGTOCONNECT; - - net->tcp_connections[con_id].outside_acknr = 0; - net->tcp_connections[con_id].outside_seqnr = - ((random() & 0xffff) << 16) + (random() & 0xffff); - } - - if (rst) { - debug("[ 'rst': disconnecting TCP connection %i ]\n", con_id); - net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1); - tcp_closeconnection(net, con_id); - return; - } - - if (ack && net->tcp_connections[con_id].state - == TCP_OUTSIDE_DISCONNECTED2) { - debug("[ 'ack': guestOS's final termination of TCP " - "connection %i ]\n", con_id); - - /* Send an RST? (TODO, this is wrong...) */ - net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1); - - /* ... and forget about this connection: */ - tcp_closeconnection(net, con_id); - return; - } - - if (fin && net->tcp_connections[con_id].state - == TCP_OUTSIDE_DISCONNECTED) { - debug("[ 'fin': response to outside's disconnection of " - "TCP connection %i ]\n", con_id); - - /* Send an ACK: */ - net->tcp_connections[con_id].state = TCP_OUTSIDE_CONNECTED; - net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); - net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2; - return; - } - - if (fin) { - debug("[ 'fin': guestOS disconnecting TCP connection %i ]\n", - con_id); - - /* Send ACK: */ - net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); - net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2; - - /* Return and send FIN: */ - goto ret; - } - - if (ack) { -debug("ACK %i bytes, inside_acknr=%u outside_seqnr=%u\n", - net->tcp_connections[con_id].incoming_buf_len, - net->tcp_connections[con_id].inside_acknr, - net->tcp_connections[con_id].outside_seqnr); - net->tcp_connections[con_id].inside_acknr = acknr; - if (net->tcp_connections[con_id].inside_acknr == - net->tcp_connections[con_id].outside_seqnr && - net->tcp_connections[con_id].incoming_buf_len != 0) { -debug(" all acked\n"); - net->tcp_connections[con_id].incoming_buf_len = 0; - } - } - - net->tcp_connections[con_id].inside_seqnr = seqnr; - - /* TODO: This is hardcoded for a specific NetBSD packet: */ - if (packet[34 + 30] == 0x08 && packet[34 + 31] == 0x0a) - net->tcp_connections[con_id].inside_timestamp = - (packet[34 + 32 + 0] << 24) + - (packet[34 + 32 + 1] << 16) + - (packet[34 + 32 + 2] << 8) + - (packet[34 + 32 + 3] << 0); - - - net->timestamp ++; - net->tcp_connections[con_id].last_used_timestamp = net->timestamp; - - - if (net->tcp_connections[con_id].state != TCP_OUTSIDE_CONNECTED) { - debug("[ not connected to outside ]\n"); - return; - } - - - if (data_offset >= len) - return; - - - /* - * We are here if this is a known connection, and data is to be - * transmitted to the outside world. - */ - - send_ofs = data_offset; - send_ofs += ((int32_t)net->tcp_connections[con_id].outside_acknr - - (int32_t)seqnr); -#if 1 - debug("[ %i bytes of tcp data to be sent, beginning at seqnr %u, ", - len - data_offset, seqnr); - debug("outside is at acknr %u ==> %i actual bytes to be sent ]\n", - net->tcp_connections[con_id].outside_acknr, len - send_ofs); -#endif - - /* Drop outgoing packet if the guest OS' seqnr is not - the same as we have acked. (We have missed something, perhaps.) */ - if (seqnr != net->tcp_connections[con_id].outside_acknr) { - debug("!! outgoing TCP packet dropped (seqnr = %u, " - "outside_acknr = %u)\n", seqnr, - net->tcp_connections[con_id].outside_acknr); - goto ret; - } - - if (len - send_ofs > 0) { - /* Is the socket available for output? */ - FD_ZERO(&rfds); /* write */ - FD_SET(net->tcp_connections[con_id].socket, &rfds); - tv.tv_sec = tv.tv_usec = 0; - errno = 0; - res = select(net->tcp_connections[con_id].socket+1, - NULL, &rfds, NULL, &tv); - if (res < 1) { - net->tcp_connections[con_id].state = - TCP_OUTSIDE_DISCONNECTED; - debug("[ TCP: disconnect on select for writing ]\n"); - goto ret; - } - - res = write(net->tcp_connections[con_id].socket, - packet + send_ofs, len - send_ofs); - - if (res > 0) { - net->tcp_connections[con_id].outside_acknr += res; - } else if (errno == EAGAIN) { - /* Just ignore this attempt. */ - return; - } else { - debug("[ error writing %i bytes to TCP connection %i:" - " errno = %i ]\n", len - send_ofs, con_id, errno); - net->tcp_connections[con_id].state = - TCP_OUTSIDE_DISCONNECTED; - debug("[ TCP: disconnect on write() ]\n"); - goto ret; - } - } - -ret: - /* Send an ACK (or FIN) to the guest OS: */ - net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0); -} - - -/* - * net_ip_udp(): - * - * Handle a UDP packet. - * - * (See http://www.networksorcery.com/enp/protocol/udp.htm.) - * - * The IP header (at offset 14) could look something like - * - * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798 - * src=0a000001 dst=c1abcdef - * - * and the UDP data (beginning at offset 34): - * - * srcport=fffc dstport=0035 length=0028 chksum=76b6 - * 43e20100000100000000000003667470066e6574627364036f726700001c0001 - */ -static void net_ip_udp(struct net *net, void *extra, - unsigned char *packet, int len) -{ - int con_id, free_con_id, i, srcport, dstport, udp_len; - ssize_t res; - struct sockaddr_in remote_ip; - - if ((packet[20] & 0x3f) != 0) { - fatal("[ net_ip_udp(): WARNING! fragmented UDP " - "packet, TODO ]\n"); - return; - } - - srcport = (packet[34] << 8) + packet[35]; - dstport = (packet[36] << 8) + packet[37]; - udp_len = (packet[38] << 8) + packet[39]; - /* chksum at offset 40 and 41 */ - - debug("[ net: UDP: "); - debug("srcport=%i dstport=%i len=%i ", srcport, dstport, udp_len); - for (i=42; i= ' ' && packet[i] < 127) - debug("%c", packet[i]); - else - debug("[%02x]", packet[i]); - } - debug(" ]\n"); - - /* Is this "connection" new, or a currently ongoing one? */ - con_id = free_con_id = -1; - for (i=0; iudp_connections[i].in_use) - free_con_id = i; - if (net->udp_connections[i].in_use && - net->udp_connections[i].inside_udp_port == srcport && - net->udp_connections[i].outside_udp_port == dstport && - memcmp(net->udp_connections[i].inside_ip_address, - packet + 26, 4) == 0 && - memcmp(net->udp_connections[i].outside_ip_address, - packet + 30, 4) == 0) { - con_id = i; - break; - } - } - - debug("&& UDP connection is "); - if (con_id >= 0) - debug("ONGOING"); - else { - debug("NEW"); - if (free_con_id < 0) { - int64_t oldest = net-> - udp_connections[0].last_used_timestamp; - free_con_id = 0; - - debug(", NO FREE SLOTS, REUSING OLDEST ONE"); - for (int j=0; judp_connections[j].last_used_timestamp < oldest) { - oldest = net->udp_connections[j].last_used_timestamp; - free_con_id = j; - } - - close(net->udp_connections[free_con_id].socket); - } - con_id = free_con_id; - memset(&net->udp_connections[con_id], 0, - sizeof(struct udp_connection)); - - memcpy(net->udp_connections[con_id].ethernet_address, - packet + 6, 6); - memcpy(net->udp_connections[con_id].inside_ip_address, - packet + 26, 4); - net->udp_connections[con_id].inside_udp_port = srcport; - memcpy(net->udp_connections[con_id].outside_ip_address, - packet + 30, 4); - net->udp_connections[con_id].outside_udp_port = dstport; - - net->udp_connections[con_id].socket = socket(AF_INET, - SOCK_DGRAM, 0); - if (net->udp_connections[con_id].socket < 0) { - fatal("[ net: UDP: socket() returned %i ]\n", - net->udp_connections[con_id].socket); - return; - } - - debug(" {socket=%i}", net->udp_connections[con_id].socket); - - net->udp_connections[con_id].in_use = 1; - - /* Set the socket to non-blocking: */ - res = fcntl(net->udp_connections[con_id].socket, F_GETFL); - fcntl(net->udp_connections[con_id].socket, F_SETFL, - res | O_NONBLOCK); - } - - debug(", connection id %i\n", con_id); - - net->timestamp ++; - net->udp_connections[con_id].last_used_timestamp = net->timestamp; - - remote_ip.sin_family = AF_INET; - memcpy((unsigned char *)&remote_ip.sin_addr, - net->udp_connections[con_id].outside_ip_address, 4); - - /* - * Special case for the nameserver: If a UDP packet is sent to - * the gateway, it will be forwarded to the nameserver, if it is - * known. - */ - if (net->nameserver_known && - memcmp(net->udp_connections[con_id].outside_ip_address, - &net->gateway_ipv4_addr[0], 4) == 0) { - memcpy((unsigned char *)&remote_ip.sin_addr, - &net->nameserver_ipv4, 4); - net->udp_connections[con_id].fake_ns = 1; - } - - remote_ip.sin_port = htons( - net->udp_connections[con_id].outside_udp_port); - - res = sendto(net->udp_connections[con_id].socket, packet + 42, - len - 42, 0, (const struct sockaddr *)&remote_ip, - sizeof(remote_ip)); - - if (res != len-42) - debug("[ net: UDP: unable to send %i bytes ]\n", len-42); - else - debug("[ net: UDP: OK!!! ]\n"); -} - - -/* - * net_ip(): - * - * Handle an IP packet, coming from the emulated NIC. - */ -void net_ip(struct net *net, void *extra, unsigned char *packet, int len) -{ -#if 1 - int i; - - debug("[ net: IP: "); - debug("ver=%02x ", packet[14]); - debug("tos=%02x ", packet[15]); - debug("len=%02x%02x ", packet[16], packet[17]); - debug("id=%02x%02x ", packet[18], packet[19]); - debug("ofs=%02x%02x ", packet[20], packet[21]); - debug("ttl=%02x ", packet[22]); - debug("p=%02x ", packet[23]); - debug("sum=%02x%02x ", packet[24], packet[25]); - debug("src=%02x%02x%02x%02x ", - packet[26], packet[27], packet[28], packet[29]); - debug("dst=%02x%02x%02x%02x ", - packet[30], packet[31], packet[32], packet[33]); - for (i=34; i 14 + packet[16]*256 + packet[17]) - len = 14 + packet[16]*256 + packet[17]; - - if (packet[14] == 0x45) { - /* IPv4: */ - switch (packet[23]) { - case 1: /* ICMP */ - net_ip_icmp(net, extra, packet, len); - break; - case 6: /* TCP */ - net_ip_tcp(net, extra, packet, len); - break; - case 17:/* UDP */ - net_ip_udp(net, extra, packet, len); - break; - default: - fatal("[ net: IP: UNIMPLEMENTED protocol %i ]\n", - packet[23]); - } - } else - fatal("[ net: IP: UNIMPLEMENTED ip, first byte = 0x%02x ]\n", - packet[14]); -} - - -/* - * net_ip_broadcast_dhcp(): - * - * Handle an IPv4 DHCP broadcast packet, coming from the emulated NIC. - * - * Read http://tools.ietf.org/html/rfc2131 for details on DHCP. - * (And http://users.telenet.be/mydotcom/library/network/dhcp.htm.) - */ -static void net_ip_broadcast_dhcp(struct net *net, void *extra, - unsigned char *packet, int len) -{ - /* - * TODO - */ -#if 1 - struct ethernet_packet_link *lp; - int i, reply_len; - - fatal("[ net: IPv4 DHCP: "); -#if 1 - fatal("ver=%02x ", packet[14]); - fatal("tos=%02x ", packet[15]); - fatal("len=%02x%02x ", packet[16], packet[17]); - fatal("id=%02x%02x ", packet[18], packet[19]); - fatal("ofs=%02x%02x ", packet[20], packet[21]); - fatal("ttl=%02x ", packet[22]); - fatal("p=%02x ", packet[23]); - fatal("sum=%02x%02x ", packet[24], packet[25]); -#endif - fatal("src=%02x%02x%02x%02x ", - packet[26], packet[27], packet[28], packet[29]); - fatal("dst=%02x%02x%02x%02x ", - packet[30], packet[31], packet[32], packet[33]); -#if 0 - for (i=34; idata, packet, 278); - - /* We are sending to the client, from the gateway: */ - memcpy(lp->data + 0, packet + 6, 6); - memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); - - /* Set IP length: */ - lp->data[16] = (reply_len - 14) >> 8; - lp->data[17] = (reply_len - 14) & 0xff; - - /* Set IP addresses: */ - memcpy(lp->data + 26, &net->gateway_ipv4_addr[0], 4); - lp->data[30] = 0xff; - lp->data[31] = 0xff; - lp->data[32] = 0xff; - lp->data[33] = 0xff; - - /* Switch src and dst ports: */ - memcpy(lp->data + 34, packet + 36, 2); - memcpy(lp->data + 36, packet + 34, 2); - - /* Set UDP length: */ - lp->data[38] = (reply_len - 34) >> 8; - lp->data[39] = (reply_len - 34) & 0xff; - - /* Client's (yiaddr) IPv4 address: */ - lp->data[58] = 10; - lp->data[59] = 0; - lp->data[60] = 0; - lp->data[61] = 1; - - /* Server's IPv4 address: (giaddr) */ - memcpy(lp->data + 66, &net->gateway_ipv4_addr[0], 4); - - /* This is a Reply: */ - lp->data[42] = 0x02; - - snprintf((char *)lp->data + 70+16+64, 8, "gxemul"); - - /* Options field at offset 278: */ - lp->data[278] = 99; - lp->data[279] = 130; - lp->data[280] = 83; - lp->data[281] = 99; - - /* DHCP options, http://tools.ietf.org/html/rfc1533 */ - lp->data[282] = 1; /* subnet mask */ - lp->data[283] = 4; - lp->data[284] = 255; - lp->data[285] = 0; - lp->data[286] = 0; - lp->data[287] = 0; - lp->data[288] = 3; /* router */ - lp->data[289] = 4; - memcpy(lp->data + 290, &net->gateway_ipv4_addr[0], 4); - lp->data[294] = 6; /* domain name server */ - lp->data[295] = 4; - memcpy(lp->data + 296, &net->gateway_ipv4_addr[0], 4); - lp->data[300] = 54; /* server identifier */ - lp->data[301] = 4; - memcpy(lp->data + 302, &net->gateway_ipv4_addr[0], 4); - lp->data[306] = 255; /* end */ - - /* Recalculate IP header checksum: */ - net_ip_checksum(lp->data + 14, 10, 20); - - /* ... and the UDP checksum: */ - net_ip_tcp_checksum(lp->data + 34, 6, reply_len - 34, - lp->data + 26, lp->data + 30, 1); - - -/* Debug dump: */ -packet = lp->data; - fatal("[ net: IPv4 DHCP REPLY: "); - for (i=0; i<14; i++) - fatal("%02x", packet[i]); - fatal("ver=%02x ", packet[14]); - fatal("tos=%02x ", packet[15]); - fatal("len=%02x%02x ", packet[16], packet[17]); - fatal("id=%02x%02x ", packet[18], packet[19]); - fatal("ofs=%02x%02x ", packet[20], packet[21]); - fatal("ttl=%02x ", packet[22]); - fatal("p=%02x ", packet[23]); - fatal("sum=%02x%02x ", packet[24], packet[25]); - fatal("src=%02x%02x%02x%02x ", - packet[26], packet[27], packet[28], packet[29]); - fatal("dst=%02x%02x%02x%02x ", - packet[30], packet[31], packet[32], packet[33]); - fatal("op=%02x ", packet[42]); - fatal("htype=%02x ", packet[43]); - fatal("hlen=%02x ", packet[44]); - fatal("hops=%02x ", packet[45]); - fatal("xid=%02x%02x%02x%02x ", packet[46], packet[47], - packet[48], packet[49]); - fatal("secs=%02x%02x ", packet[50], packet[51]); - fatal("flags=%02x%02x ", packet[52], packet[53]); - fatal("ciaddr=%02x%02x%02x%02x ", packet[54], packet[55], - packet[56], packet[57]); - fatal("yiaddr=%02x%02x%02x%02x ", packet[58], packet[59], - packet[60], packet[61]); - fatal("siaddr=%02x%02x%02x%02x ", packet[62], packet[63], - packet[64], packet[65]); - fatal("giaddr=%02x%02x%02x%02x ", packet[66], packet[67], - packet[68], packet[69]); - fatal("chaddr="); - for (i=70; i<70+16; i++) - fatal("%02x", packet[i]); - fatal(" ]\n"); - -#endif -} - - -/* - * net_ip_broadcast(): - * - * Handle an IP broadcast packet, coming from the emulated NIC. - * (This is usually a DHCP request, or similar.) - */ -void net_ip_broadcast(struct net *net, void *extra, - unsigned char *packet, int len) -{ - unsigned char *p = (unsigned char *) &net->netmask_ipv4; - uint32_t x, y; - int i, xl, warning = 0, match = 0; - -#if 0 - fatal("[ net: IP BROADCAST: "); - fatal("ver=%02x ", packet[14]); - fatal("tos=%02x ", packet[15]); - fatal("len=%02x%02x ", packet[16], packet[17]); - fatal("id=%02x%02x ", packet[18], packet[19]); - fatal("ofs=%02x%02x ", packet[20], packet[21]); - fatal("ttl=%02x ", packet[22]); - fatal("p=%02x ", packet[23]); - fatal("sum=%02x%02x ", packet[24], packet[25]); - fatal("src=%02x%02x%02x%02x ", - packet[26], packet[27], packet[28], packet[29]); - fatal("dst=%02x%02x%02x%02x ", - packet[30], packet[31], packet[32], packet[33]); - for (i=34; inetmask_ipv4_len; - x |= (1 << xl) - 1; - /* x = 10.255.255.255 */ - - if (x == y) - match = 1; - if (y == 0xffffffff) - match = 1; - - if (warning) - fatal("[ net_ip_broadcast(): warning: broadcast to " - "0x%08x, expecting broadcast to 0x%08x or " - "0xffffffff ]\n", y, x); - - /* Cut off overflowing tail data: */ - if (len > 14 + packet[16]*256 + packet[17]) - len = 14 + packet[16]*256 + packet[17]; - - /* Check for known packets: */ - if (packet[14] == 0x45 && /* IPv4 */ - packet[23] == 0x11 && /* UDP */ - packet[34] == 0 && packet[35] == 68 && /* DHCP client */ - packet[36] == 0 && packet[37] == 67) { /* DHCP server */ - net_ip_broadcast_dhcp(net, extra, packet, len); - return; - } - - /* Unknown packet: */ - fatal("[ net: UNIMPLEMENTED IP BROADCAST: "); - fatal("ver=%02x ", packet[14]); - fatal("tos=%02x ", packet[15]); - fatal("len=%02x%02x ", packet[16], packet[17]); - fatal("id=%02x%02x ", packet[18], packet[19]); - fatal("ofs=%02x%02x ", packet[20], packet[21]); - fatal("ttl=%02x ", packet[22]); - fatal("p=%02x ", packet[23]); - fatal("sum=%02x%02x ", packet[24], packet[25]); - fatal("src=%02x%02x%02x%02x ", - packet[26], packet[27], packet[28], packet[29]); - fatal("dst=%02x%02x%02x%02x ", - packet[30], packet[31], packet[32], packet[33]); - for (i=34; i max_packets_this_tick) - break; - - if (!net->udp_connections[con_id].in_use) - continue; - - if (net->udp_connections[con_id].socket < 0) { - fatal("INTERNAL ERROR in net.c, udp socket < 0 " - "but in use?\n"); - continue; - } - - res = recvfrom(net->udp_connections[con_id].socket, buf, - sizeof(buf), 0, (struct sockaddr *)&from, &from_len); - - /* No more incoming UDP on this connection? */ - if (res < 0) - continue; - - net->timestamp ++; - net->udp_connections[con_id].last_used_timestamp = - net->timestamp; - - net->udp_connections[con_id].udp_id ++; - - /* - * Special case for the nameserver: If a UDP packet is - * received from the nameserver (if the nameserver's IP is - * known), fake it so that it comes from the gateway instead. - */ - if (net->udp_connections[con_id].fake_ns) - memcpy(((unsigned char *)(&from))+4, - &net->gateway_ipv4_addr[0], 4); - - /* - * We now have a UDP packet of size 'res' which we need - * turn into one or more ethernet packets for the emulated - * operating system. Ethernet packets are at most 1518 - * bytes long. With some margin, that means we can have - * about 1500 bytes per packet. - * - * Ethernet = 14 bytes - * IP = 20 bytes - * (UDP = 8 bytes + data) - * - * So data can be at most max_per_packet - 34. For UDP - * fragments, each multiple should (?) be a multiple of - * 8 bytes, except the last which doesn't have any such - * restriction. - */ - max_per_packet = 1500; - - /* UDP: */ - udp_len = res + 8; - /* from[2..3] = outside_udp_port */ - udp_data[0] = ((unsigned char *)&from)[2]; - udp_data[1] = ((unsigned char *)&from)[3]; - udp_data[2] = (net->udp_connections[con_id]. - inside_udp_port >> 8) & 0xff; - udp_data[3] = net->udp_connections[con_id]. - inside_udp_port & 0xff; - udp_data[4] = udp_len >> 8; - udp_data[5] = udp_len & 0xff; - udp_data[6] = 0; - udp_data[7] = 0; - memcpy(udp_data + 8, buf, res); - /* - * TODO: UDP checksum, if necessary. At least NetBSD - * and OpenBSD accept UDP packets with 0x0000 in the - * checksum field anyway. - */ - - while (bytes_converted < udp_len) { - this_packets_data_length = udp_len - bytes_converted; - - /* Do we need to fragment? */ - if (this_packets_data_length > max_per_packet-34) { - this_packets_data_length = - max_per_packet - 34; - while (this_packets_data_length & 7) - this_packets_data_length --; - } - - ip_len = 20 + this_packets_data_length; - - lp = net_allocate_ethernet_packet_link(net, extra, - 14 + 20 + this_packets_data_length); - - /* Ethernet header: */ - memcpy(lp->data + 0, net->udp_connections[con_id]. - ethernet_address, 6); - memcpy(lp->data + 6, net->gateway_ethernet_addr, 6); - lp->data[12] = 0x08; /* IP = 0x0800 */ - lp->data[13] = 0x00; - - /* IP header: */ - lp->data[14] = 0x45; /* ver */ - lp->data[15] = 0x00; /* tos */ - lp->data[16] = ip_len >> 8; - lp->data[17] = ip_len & 0xff; - lp->data[18] = net->udp_connections[con_id].udp_id >> 8; - lp->data[19] = net->udp_connections[con_id].udp_id - & 0xff; - lp->data[20] = (fragment_ofs >> 8); - if (bytes_converted + this_packets_data_length - < udp_len) - lp->data[20] |= 0x20; /* More fragments */ - lp->data[21] = fragment_ofs & 0xff; - lp->data[22] = 0x40; /* ttl */ - lp->data[23] = 17; /* p = UDP */ - lp->data[26] = ((unsigned char *)&from)[4]; - lp->data[27] = ((unsigned char *)&from)[5]; - lp->data[28] = ((unsigned char *)&from)[6]; - lp->data[29] = ((unsigned char *)&from)[7]; - memcpy(lp->data + 30, net->udp_connections[con_id]. - inside_ip_address, 4); - net_ip_checksum(lp->data + 14, 10, 20); - - memcpy(lp->data+34, udp_data + bytes_converted, - this_packets_data_length); - - bytes_converted += this_packets_data_length; - fragment_ofs = bytes_converted / 8; - - received_packets_this_tick ++; - } - - /* This makes sure we check this connection AGAIN - for more incoming UDP packets, before moving to the - next connection: */ - con_id --; - } -} - - -/* - * net_tcp_rx_avail(): - * - * Receive any available TCP packets (from the outside world). - */ -void net_tcp_rx_avail(struct net *net, void *extra) -{ - int received_packets_this_tick = 0; - int max_packets_this_tick = 200; - int con_id; - - for (con_id=0; con_id max_packets_this_tick) - break; - - if (!net->tcp_connections[con_id].in_use) - continue; - - if (net->tcp_connections[con_id].socket < 0) { - fatal("INTERNAL ERROR in net.c, tcp socket < 0" - " but in use?\n"); - continue; - } - - if (net->tcp_connections[con_id].incoming_buf == NULL) - CHECK_ALLOCATION(net->tcp_connections[con_id]. - incoming_buf = (unsigned char *) malloc(TCP_INCOMING_BUF_LEN)); - - if (net->tcp_connections[con_id].state >= - TCP_OUTSIDE_DISCONNECTED) - continue; - - /* Is the socket available for output? */ - FD_ZERO(&rfds); /* write */ - FD_SET(net->tcp_connections[con_id].socket, &rfds); - tv.tv_sec = tv.tv_usec = 0; - errno = 0; - res = select(net->tcp_connections[con_id].socket+1, - NULL, &rfds, NULL, &tv); - - if (errno == ECONNREFUSED) { - fatal("[ ECONNREFUSED: TODO ]\n"); - net->tcp_connections[con_id].state = - TCP_OUTSIDE_DISCONNECTED; - fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED " - "(refused connection)\n"); - continue; - } - - if (errno == ETIMEDOUT) { - fatal("[ ETIMEDOUT: TODO ]\n"); - /* TODO */ - net->tcp_connections[con_id].state = - TCP_OUTSIDE_DISCONNECTED; - fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED " - "(timeout)\n"); - continue; - } - - if (net->tcp_connections[con_id].state == - TCP_OUTSIDE_TRYINGTOCONNECT && res > 0) { - net->tcp_connections[con_id].state = - TCP_OUTSIDE_CONNECTED; - debug("CHANGING TO TCP_OUTSIDE_CONNECTED\n"); - net_ip_tcp_connectionreply(net, extra, con_id, 1, - NULL, 0, 0); - } - - if (net->tcp_connections[con_id].state == - TCP_OUTSIDE_CONNECTED && res < 1) { - continue; - } - - /* - * Does this connection have unacknowledged data? Then, if - * enough number of rounds have passed, try to resend it using - * the old value of seqnr. - */ - if (net->tcp_connections[con_id].incoming_buf_len != 0) { - net->tcp_connections[con_id].incoming_buf_rounds ++; - if (net->tcp_connections[con_id].incoming_buf_rounds > - 10000) { - debug(" at seqnr %u but backing back to %u," - " resending %i bytes\n", - net->tcp_connections[con_id].outside_seqnr, - net->tcp_connections[con_id]. - incoming_buf_seqnr, - net->tcp_connections[con_id]. - incoming_buf_len); - - net->tcp_connections[con_id]. - incoming_buf_rounds = 0; - net->tcp_connections[con_id].outside_seqnr = - net->tcp_connections[con_id]. - incoming_buf_seqnr; - - net_ip_tcp_connectionreply(net, extra, con_id, - 0, net->tcp_connections[con_id]. - incoming_buf, - net->tcp_connections[con_id]. - incoming_buf_len, 0); - } - continue; - } - - /* Don't receive unless the guest OS is ready! */ - if (((int32_t)net->tcp_connections[con_id].outside_seqnr - - (int32_t)net->tcp_connections[con_id].inside_acknr) > 0) { -/* fatal("YOYO 1! outside_seqnr - inside_acknr = %i\n", - net->tcp_connections[con_id].outside_seqnr - - net->tcp_connections[con_id].inside_acknr); */ - continue; - } - - /* Is there incoming data available on the socket? */ - FD_ZERO(&rfds); /* read */ - FD_SET(net->tcp_connections[con_id].socket, &rfds); - tv.tv_sec = tv.tv_usec = 0; - res2 = select(net->tcp_connections[con_id].socket+1, &rfds, - NULL, NULL, &tv); - - /* No more incoming TCP data on this connection? */ - if (res2 < 1) - continue; - - res = read(net->tcp_connections[con_id].socket, buf, 1400); - if (res > 0) { - /* debug("\n -{- %lli -}-\n", (long long)res); */ - net->tcp_connections[con_id].incoming_buf_len = res; - net->tcp_connections[con_id].incoming_buf_rounds = 0; - net->tcp_connections[con_id].incoming_buf_seqnr = - net->tcp_connections[con_id].outside_seqnr; - debug(" putting %i bytes (seqnr %u) in the incoming " - "buf\n", res, net->tcp_connections[con_id]. - incoming_buf_seqnr); - memcpy(net->tcp_connections[con_id].incoming_buf, - buf, res); - - net_ip_tcp_connectionreply(net, extra, con_id, 0, - buf, res, 0); - } else if (res == 0) { - net->tcp_connections[con_id].state = - TCP_OUTSIDE_DISCONNECTED; - debug("CHANGING TO TCP_OUTSIDE_DISCONNECTED, read" - " res=0\n"); - net_ip_tcp_connectionreply(net, extra, con_id, 0, - NULL, 0, 0); - } else { - net->tcp_connections[con_id].state = - TCP_OUTSIDE_DISCONNECTED; - fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED, " - "read res<=0, errno = %i\n", errno); - net_ip_tcp_connectionreply(net, extra, con_id, 0, - NULL, 0, 0); - } - - net->timestamp ++; - net->tcp_connections[con_id].last_used_timestamp = - net->timestamp; - } -} - - diff -Nru gxemul-0.6.2/src/net/net_misc.c gxemul-0.7.0+dfsg/src/net/net_misc.c --- gxemul-0.6.2/src/net/net_misc.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net_misc.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2004-2018 Anders Gavare. 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. The name of the author 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. + * + * + * Misc. helper functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "machine.h" +#include "misc.h" +#include "net.h" + + +/* + * net_debugaddr(): + * + * Print an address using debug(). + */ +void net_debugaddr(void *addr, int type) +{ + int i; + unsigned char *p = (unsigned char *) addr; + + switch (type) { + + case NET_ADDR_IPV4: + for (i=0; i<4; i++) + debug("%s%i", i? "." : "", p[i]); + break; + + case NET_ADDR_IPV6: + for (i=0; i<16; i+=2) + debug("%s%4x", i? ":" : "", p[i] * 256 + p[i+1]); + break; + + case NET_ADDR_ETHERNET: + for (i=0; i<6; i++) + debug("%s%02x", i? ":" : "", p[i]); + break; + + default: + fatal("net_debugaddr(): UNIMPLEMTED type %i\n", type); + exit(1); + } +} + + +/* + * net_generate_unique_mac(): + * + * Generate a "unique" serial number for a machine. The machine's serial + * number is combined with the machine's current number of NICs to form a + * more-or-less valid MAC address. + * + * The return value (6 bytes) are written to macbuf. + */ +void net_generate_unique_mac(struct machine *machine, unsigned char *macbuf) +{ + if (macbuf == NULL || machine == NULL) { + fatal("**\n** net_generate_unique_mac(): NULL ptr\n**\n"); + return; + } + + // Special case: real SGI machines have 0x08 as their first + // byte, so let's mimic that. + macbuf[0] = machine->machine_type == MACHINE_SGI ? 0x08 : 0x10; + macbuf[1] = 0x20; + macbuf[2] = 0x30; + macbuf[3] = 0; + macbuf[4] = 0; + /* NOTE/TODO: This only allows 8 nics per machine! */ + macbuf[5] = (machine->serial_nr << 4) + (machine->nr_of_nics << 1); + + if (macbuf[0] & 1 || macbuf[5] & 1) { + fatal("Internal error in net_generate_unique_mac().\n"); + exit(1); + } + + /* TODO: Remember the mac addresses somewhere? */ + machine->nr_of_nics ++; +} + + +/* + * send_udp(): + * + * Send a simple UDP packet to a real (physical) host. Used for distributed + * network simulations. + */ +void send_udp(struct in_addr *addrp, int portnr, unsigned char *packet, size_t len) +{ + int s; + struct sockaddr_in si; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + perror("send_udp(): socket"); + return; + } + + /* fatal("send_udp(): sending to port %i\n", portnr); */ + + si.sin_family = AF_INET; + si.sin_addr = *addrp; + si.sin_port = htons(portnr); + + if (sendto(s, packet, len, 0, (struct sockaddr *)&si, + sizeof(si)) != (ssize_t)len) { + perror("send_udp(): sendto"); + } + + close(s); +} + diff -Nru gxemul-0.6.2/src/net/net_misc.cc gxemul-0.7.0+dfsg/src/net/net_misc.cc --- gxemul-0.6.2/src/net/net_misc.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net_misc.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2004-2018 Anders Gavare. 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. The name of the author 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. - * - * - * Misc. helper functions. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "machine.h" -#include "misc.h" -#include "net.h" - - -/* - * net_debugaddr(): - * - * Print an address using debug(). - */ -void net_debugaddr(void *addr, int type) -{ - int i; - unsigned char *p = (unsigned char *) addr; - - switch (type) { - - case NET_ADDR_IPV4: - for (i=0; i<4; i++) - debug("%s%i", i? "." : "", p[i]); - break; - - case NET_ADDR_IPV6: - for (i=0; i<16; i+=2) - debug("%s%4x", i? ":" : "", p[i] * 256 + p[i+1]); - break; - - case NET_ADDR_ETHERNET: - for (i=0; i<6; i++) - debug("%s%02x", i? ":" : "", p[i]); - break; - - default: - fatal("net_debugaddr(): UNIMPLEMTED type %i\n", type); - exit(1); - } -} - - -/* - * net_generate_unique_mac(): - * - * Generate a "unique" serial number for a machine. The machine's serial - * number is combined with the machine's current number of NICs to form a - * more-or-less valid MAC address. - * - * The return value (6 bytes) are written to macbuf. - */ -void net_generate_unique_mac(struct machine *machine, unsigned char *macbuf) -{ - int x, y; - - if (macbuf == NULL || machine == NULL) { - fatal("**\n** net_generate_unique_mac(): NULL ptr\n**\n"); - return; - } - - x = machine->serial_nr; - y = machine->nr_of_nics; - - // Special case: SGI machines have 0x08 as their first byte? - macbuf[0] = machine->machine_type == MACHINE_SGI ? 0x08 : 0x10; - macbuf[1] = 0x20; - macbuf[2] = 0x30; - macbuf[3] = 0; - macbuf[4] = 0; - /* NOTE/TODO: This only allows 8 nics per machine! */ - macbuf[5] = (machine->serial_nr << 4) + (machine->nr_of_nics << 1); - - if (macbuf[0] & 1 || macbuf[5] & 1) { - fatal("Internal error in net_generate_unique_mac().\n"); - exit(1); - } - - /* TODO: Remember the mac addresses somewhere? */ - machine->nr_of_nics ++; -} - - -/* - * send_udp(): - * - * Send a simple UDP packet to a real (physical) host. Used for distributed - * network simulations. - */ -void send_udp(struct in_addr *addrp, int portnr, unsigned char *packet, - size_t len) -{ - int s; - struct sockaddr_in si; - - s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) { - perror("send_udp(): socket"); - return; - } - - /* fatal("send_udp(): sending to port %i\n", portnr); */ - - si.sin_family = AF_INET; - si.sin_addr = *addrp; - si.sin_port = htons(portnr); - - if (sendto(s, packet, len, 0, (struct sockaddr *)&si, - sizeof(si)) != (ssize_t)len) { - perror("send_udp(): sendto"); - } - - close(s); -} - diff -Nru gxemul-0.6.2/src/net/net_tap.c gxemul-0.7.0+dfsg/src/net/net_tap.c --- gxemul-0.6.2/src/net/net_tap.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/net_tap.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2020 Jason R. Thorpe. 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. The name of the author 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. + */ + +/* + * Support for Ethernet tap interfaces. + * + * A single tap instance is used for the entire simulated network. + * We treat this as sort of virtual Ethernet switch, with the tap + * being the upstream port. This is very simple, conceptually, and + * fits in nicely with the rest of the network simulation model in + * GXemul. + * + * Use of the tap interface is completely optional, but if it is used + * then all of the virtual IP network support is bypassed completely. + */ + +#include +#include +#include +#include +#include +#include + +#include "misc.h" +#include "net.h" + +/* + * net_tap_rx_for_nic(): + * + * Receive a packet from the virtual Ethernet switch for this NIC. + */ +static void net_tap_rx_for_nic(struct net *net, struct nic_data *nic, + unsigned char *buf, ssize_t size) +{ + struct ethernet_packet_link *lp; + + /* + * We should deliver to the interface if: + * + * ==> The interface is in promiscuous mode. + * -- or -- + * ==> The packet is broadcast or multicast (the emulated device + * can further apply a multicast filter if it wishes). + * -- or -- + * ==> The destination MAC address matches the NIC MAC address. + * + * Note that normally a switch would not know if an interface + * is in promiscuous mode, but this is a bit of extra magic + * we implement because we can for the sake of convenience. + * Also, some emulated interfaces may want to see all packets + * so as to implement their own filtering logic. + * + * Also note that testing for multicast also catches the broadcast + * case. + */ + + if (nic->promiscuous_mode || + net_ether_multicast(buf) || net_ether_eq(nic->mac_address, buf)) { + lp = net_allocate_ethernet_packet_link(net, nic, (int)size); + memcpy(lp->data, buf, size); + } +} + +/* + * net_tap_rx_avail(): + * + * We poll the net-shared tap device and link up any available packets to + * their destination interfaces, acting like a virtual Ethernet switch. + */ +void net_tap_rx_avail(struct net *net) +{ + int received_packets_this_tick = 0; + int max_packets_this_tick = 200; + + for (;;) { + unsigned char buf[1518]; + ssize_t bytes_read; + int i; + + if (received_packets_this_tick > max_packets_this_tick) + break; + + /* Read one packet from the tap device. */ + bytes_read = read(net->tap_fd, buf, sizeof(buf)); + + if (bytes_read < 0) { + /* No more packets available on the tap. */ + break; + } + + /* + * Drop runt packets now; allow other layers to assume + * valid Ethernet frames. This really should be 64, but + * 20 is used in the transmit path. + */ + if (bytes_read < 20) + continue; + + for (i = 0; i < net->n_nics; i++) { + net_tap_rx_for_nic(net, net->nic_data[i], + buf, bytes_read); + } + } +} + +/* + * net_tap_tx(): + * + * Transmit an ethernet packet, as seen from the emulated ethernet controller, + * to the net-shared tap device. Even if the packet is destined only for + * a NIC on the local virtual Ethernet switch, we always send it to the + * tap device so that the host system can monitor traffic by running tcpdump + * on its view of the tap. + */ +void net_tap_tx(struct net *net, struct nic_data *nic, + unsigned char *packet, int len) +{ + int i; + + for (i = 0; i < net->n_nics; i++) { + if (nic == net->nic_data[i]) + continue; + net_tap_rx_for_nic(net, net->nic_data[i], packet, len); + } + + /* + * Don't bother checking for errors here. The tap driver in the + * kernel will either take the entire packet or none of it, and + * there isn't any useful error recovery for us anyway. + */ + int ignored = write(net->tap_fd, packet, len); + (void)ignored; +} + +/* + * net_tap_init(): + * + * Initialize the tap interface. Returns true if successful, false otherwise. + */ +bool net_tap_init(struct net *net, const char *tapdev) +{ + int fd; + int one = 1; + + fd = open(tapdev, O_RDWR); + if (fd < 0) { + debugmsg(SUBSYS_NET, "tap", VERBOSITY_ERROR, + "unable to open tap device '%s': %s", + tapdev, strerror(errno)); + return false; + } + + if (ioctl(fd, FIONBIO, &one) < 0) { + debugmsg(SUBSYS_NET, "tap", VERBOSITY_ERROR, + "unable to set non-blocking mode on " + "tap device '%s': %s", tapdev, strerror(errno)); + close(fd); + return false; + } + + net->tapdev = strdup(tapdev); + net->tap_fd = fd; + + return true; +} + diff -Nru gxemul-0.6.2/src/net/README gxemul-0.7.0+dfsg/src/net/README --- gxemul-0.6.2/src/net/README 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/net/README 2021-11-27 09:42:23.000000000 +0000 @@ -1,7 +1,12 @@ Emulated (ethernet / internet) network support. -NOTE: This is just an ugly hack, and just barely enough to get some - Internet networking up and running for the guest OS. +The emulated internet gateway support is just an ugly hack, just barely +enough to get some Internet networking up and running for the guest OS. + +(The emulated internet support can be bypassed by using TAP networking. +In that case, packets from the emulated network are passed to a TAP +device, and it is up to you to make sure that any DNS hosts or other +servers are reachable.) TODO: o) TCP: fin/ack stuff, and connection time-outs and diff -Nru gxemul-0.6.2/src/old_main/emul.cc gxemul-0.7.0+dfsg/src/old_main/emul.cc --- gxemul-0.6.2/src/old_main/emul.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/emul.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,938 +0,0 @@ -/* - * Copyright (C) 2003-2018 Anders Gavare. 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. The name of the author 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. - * - * - * LEGACY emulation startup and misc. routines. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "arcbios.h" -#include "cpu.h" -#include "emul.h" -#include "console.h" -#include "debugger.h" -#include "device.h" -#include "diskimage.h" -#include "machine.h" -#include "memory.h" -#include "mips_cpu_types.h" -#include "misc.h" -#include "net.h" -#include "settings.h" -#include "timer.h" -#include "x11.h" - -#include "thirdparty/exec_elf.h" - - -extern int extra_argc; -extern char **extra_argv; - -extern int verbose; -extern int quiet_mode; -extern int force_debugger_at_exit; -extern int single_step; -extern int old_show_trace_tree; -extern int old_instruction_trace; -extern int old_quiet_mode; -extern int quiet_mode; - - -/* - * add_breakpoints(): - * - * Take the strings breakpoint_string[] and convert to addresses - * (and store them in breakpoint_addr[]). - * - * TODO: This function should be moved elsewhere. - */ -static void add_breakpoints(struct machine *m) -{ - int i; - int string_flag; - uint64_t dp; - - for (i=0; ibreakpoints.n; i++) { - string_flag = 0; - dp = strtoull(m->breakpoints.string[i], NULL, 0); - - /* - * If conversion resulted in 0, then perhaps it is a - * symbol: - */ - if (dp == 0) { - uint64_t addr; - int res = get_symbol_addr(&m->symbol_context, - m->breakpoints.string[i], &addr); - if (!res) { - fprintf(stderr, - "ERROR! Breakpoint '%s' could not be" - " parsed\n", - m->breakpoints.string[i]); - exit(1); - } else { - dp = addr; - string_flag = 1; - } - } - - /* - * TODO: It would be nice if things like symbolname+0x1234 - * were automatically converted into the correct address. - */ - - if (m->arch == ARCH_MIPS) { - if ((dp >> 32) == 0 && ((dp >> 31) & 1)) - dp |= 0xffffffff00000000ULL; - } - - m->breakpoints.addr[i] = dp; - - debug("breakpoint %i: 0x%" PRIx64, i, dp); - if (string_flag) - debug(" (%s)", m->breakpoints.string[i]); - debug("\n"); - } -} - - -/* - * fix_console(): - */ -static void fix_console(void) -{ - console_deinit_main(); -} - - -/* - * emul_new(): - * - * Returns a reasonably initialized struct emul. - */ -struct emul *emul_new(char *name) -{ - struct emul *e; - - CHECK_ALLOCATION(e = (struct emul *) malloc(sizeof(struct emul))); - memset(e, 0, sizeof(struct emul)); - - e->settings = settings_new(); - - settings_add(e->settings, "n_machines", 0, - SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, - (void *) &e->n_machines); - - /* TODO: More settings? */ - - /* Sane default values: */ - e->n_machines = 0; - e->next_serial_nr = 1; - - if (name != NULL) { - CHECK_ALLOCATION(e->name = strdup(name)); - settings_add(e->settings, "name", 0, - SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING, - (void *) &e->name); - } - - return e; -} - - -/* - * emul_destroy(): - * - * Destroys a previously created emul object. - */ -void emul_destroy(struct emul *emul) -{ - int i; - - if (emul->name != NULL) { - settings_remove(emul->settings, "name"); - free(emul->name); - } - - for (i=0; in_machines; i++) - machine_destroy(emul->machines[i]); - - if (emul->machines != NULL) - free(emul->machines); - - /* Remove any remaining level-1 settings: */ - settings_remove_all(emul->settings); - settings_destroy(emul->settings); - - free(emul); -} - - -/* - * emul_add_machine(): - * - * Calls machine_new(), adds the new machine into the emul struct, and - * returns a pointer to the new machine. - * - * This function should be used instead of manually calling machine_new(). - */ -struct machine *emul_add_machine(struct emul *e, char *name) -{ - struct machine *m; - char tmpstr[20]; - int i; - - m = machine_new(name, e, e->n_machines); - m->serial_nr = (e->next_serial_nr ++); - - i = e->n_machines ++; - - CHECK_ALLOCATION(e->machines = (struct machine **) realloc(e->machines, - sizeof(struct machine *) * e->n_machines)); - - e->machines[i] = m; - - snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i); - settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0, - e->machines[i]->settings); - - return m; -} - - -/* - * add_arc_components(): - * - * This function adds ARCBIOS memory descriptors for the loaded program, - * and ARCBIOS components for SCSI devices. - */ -static void add_arc_components(struct machine *m) -{ - struct cpu *cpu = m->cpus[m->bootstrap_cpu]; - uint64_t start = cpu->pc & 0x1fffffff; - uint64_t len = 0xc00000 - start; - struct diskimage *d; - uint64_t scsicontroller, scsidevice, scsidisk; - - if ((cpu->pc >> 60) != 0xf) { - start = cpu->pc & 0xffffffffffULL; - len = 0xc00000 - start; - } - - len += 1048576 * m->memory_offset_in_mb; - - /* - * NOTE/TODO: magic 12MB end of load program area - * - * Hm. This breaks the old FreeBSD/MIPS snapshots... - */ -#if 0 - arcbios_add_memory_descriptor(cpu, - 0x60000 + m->memory_offset_in_mb * 1048576, - start-0x60000 - m->memory_offset_in_mb * 1048576, - ARCBIOS_MEM_FreeMemory); -#endif - arcbios_add_memory_descriptor(cpu, - start, len, ARCBIOS_MEM_LoadedProgram); - - scsicontroller = arcbios_get_scsicontroller(m); - if (scsicontroller == 0) - return; - - /* TODO: The device 'name' should defined be somewhere else. */ - - d = m->first_diskimage; - while (d != NULL) { - if (d->type == DISKIMAGE_SCSI) { - int a, b, flags = COMPONENT_FLAG_Input; - char component_string[100]; - const char *name = "DEC RZ58 (C) DEC2000"; - - /* Read-write, or read-only? */ - if (d->writable) - flags |= COMPONENT_FLAG_Output; - else - flags |= COMPONENT_FLAG_ReadOnly; - - a = COMPONENT_TYPE_DiskController; - b = COMPONENT_TYPE_DiskPeripheral; - - if (d->is_a_cdrom) { - flags |= COMPONENT_FLAG_Removable; - a = COMPONENT_TYPE_CDROMController; - b = COMPONENT_TYPE_FloppyDiskPeripheral; - name = "NEC CD-ROM CDR-210P 1.0 "; - } - - scsidevice = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - a, flags, 1, 2, d->id, 0xffffffff, - name, scsicontroller, NULL, 0); - - scsidisk = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_PeripheralClass, - b, flags, 1, 2, 0, 0xffffffff, NULL, - scsidevice, NULL, 0); - - /* - * Add device string to component address mappings: - * "scsi(0)disk(0)rdisk(0)partition(0)" - */ - - if (d->is_a_cdrom) { - snprintf(component_string, - sizeof(component_string), - "scsi(0)cdrom(%i)", d->id); - arcbios_add_string_to_component(m, - component_string, scsidevice); - - snprintf(component_string, - sizeof(component_string), - "scsi(0)cdrom(%i)fdisk(0)", d->id); - arcbios_add_string_to_component(m, - component_string, scsidisk); - } else { - snprintf(component_string, - sizeof(component_string), - "scsi(0)disk(%i)", d->id); - arcbios_add_string_to_component(m, - component_string, scsidevice); - - snprintf(component_string, - sizeof(component_string), - "scsi(0)disk(%i)rdisk(0)", d->id); - arcbios_add_string_to_component(m, - component_string, scsidisk); - } - } - - d = d->next; - } -} - - -/* - * emul_machine_setup(): - * - * o) Initialize the hardware (RAM, devices, CPUs, ...) which - * will be emulated in this machine. - * - * o) Load ROM code and/or other programs into emulated memory. - * - * o) Special hacks needed after programs have been loaded. - */ -void emul_machine_setup(struct machine *m, int n_load, char **load_names, - int n_devices, char **device_names) -{ - struct cpu *cpu; - int i, iadd = DEBUG_INDENTATION; - uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0; - int byte_order; - - if (m->name != NULL) - debug("machine \"%s\":\n", m->name); - else - debug("machine:\n"); - - debug_indentation(iadd); - - if (m->machine_type == MACHINE_NONE) { - fatal("No machine type specified?\n"); - exit(1); - } - - m->cpu_family = cpu_family_ptr_by_number(m->arch); - - if (m->arch == ARCH_ALPHA) - m->arch_pagesize = 8192; - - machine_memsize_fix(m); - - /* - * Create the system's memory: - */ - debug("memory: %i MB", m->physical_ram_in_mb); - memory_amount = (uint64_t)m->physical_ram_in_mb * 1048576; - if (m->memory_offset_in_mb > 0) { - /* - * A special hack is used for some SGI models, - * where memory is offset by 128MB to leave room for - * EISA space and other things. - */ - debug(" (offset by %iMB)", m->memory_offset_in_mb); - memory_amount += 1048576 * m->memory_offset_in_mb; - } - if (m->machine_type == MACHINE_SGI && m->machine_subtype == 32) { - if (memory_amount > 0x10000000) { - memory_amount = 0x10000000; - debug(" (SGI O2 hack: %i MB at offset 0)", 0x10000000 / 1048576); - } - } - m->memory = memory_new(memory_amount, m->arch); - debug("\n"); - - /* Create CPUs: */ - if (m->cpu_name == NULL) - machine_default_cputype(m); - if (m->ncpus == 0) - m->ncpus = 1; - - CHECK_ALLOCATION(m->cpus = (struct cpu **) malloc(sizeof(struct cpu *) * m->ncpus)); - memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus); - - debug("cpu0"); - if (m->ncpus > 1) - debug(" .. cpu%i", m->ncpus - 1); - debug(": "); - for (i=0; incpus; i++) { - m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name); - if (m->cpus[i] == NULL) { - fprintf(stderr, "Unable to create CPU object. " - "Aborting."); - exit(1); - } - } - debug("\n"); - - if (m->use_random_bootstrap_cpu) - m->bootstrap_cpu = random() % m->ncpus; - else - m->bootstrap_cpu = 0; - - cpu = m->cpus[m->bootstrap_cpu]; - - if (m->x11_md.in_use) - x11_init(m); - - /* Fill the directly addressable memory with random bytes: */ - if (m->random_mem_contents) { - for (i=0; i<(int)memory_amount; i+=256) { - unsigned char data[256]; - unsigned int j; - for (j=0; jmemory_rw(cpu, m->memory, i, data, sizeof(data), - MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL); - } - } - - for (i=0; ifirst_diskimage != NULL) { - if (!load_bootblock(m, cpu, &n_load, &load_names)) { - fprintf(stderr, "\nNo executable files were" - " specified, and booting directly from disk" - " failed.\n"); - exit(1); - } - } else { - fprintf(stderr, "No executable file(s) loaded, and " - "we are not booting directly from a disk image." - "\nAborting.\n"); - exit(1); - } - } - - while (n_load > 0) { - FILE *tmp_f; - char *name_to_load = *load_names; - int remove_after_load = 0; - - /* Special hack for removing temporary files: */ - if (name_to_load[0] == 8) { - name_to_load ++; - remove_after_load = 1; - } - - /* - * gzipped files are automagically gunzipped: - * NOTE/TODO: This isn't secure. system() is used. - */ - tmp_f = fopen(name_to_load, "r"); - if (tmp_f != NULL) { - unsigned char buf[2]; /* gzip header */ - size_t res; - - memset(buf, 0, sizeof(buf)); - res = fread(buf, 1, sizeof(buf), tmp_f); - - if (res == sizeof(buf) && - buf[0] == 0x1f && buf[1] == 0x8b) { - size_t zzlen = strlen(name_to_load)*2 + 100; - char *zz; - - CHECK_ALLOCATION(zz = (char*) malloc(zzlen)); - debug("gunziping %s\n", name_to_load); - - /* - * gzip header found. If this was a file - * extracted from, say, a CDROM image, then it - * already has a temporary name. Otherwise we - * have to gunzip into a temporary file. - */ - if (remove_after_load) { - snprintf(zz, zzlen, "mv %s %s.gz", - name_to_load, name_to_load); - if (system(zz) != 0) - perror(zz); - snprintf(zz, zzlen, "gunzip %s.gz", - name_to_load); - if (system(zz) != 0) - perror(zz); - } else { - /* gunzip into new temp file: */ - int tmpfile_handle; - char *new_temp_name; - const char *tmpdir = getenv("TMPDIR"); - - if (tmpdir == NULL) - tmpdir = DEFAULT_TMP_DIR; - - CHECK_ALLOCATION(new_temp_name = - (char*) malloc(300)); - snprintf(new_temp_name, 300, - "%s/gxemul.XXXXXXXXXXXX", tmpdir); - - tmpfile_handle = mkstemp(new_temp_name); - close(tmpfile_handle); - snprintf(zz, zzlen, "gunzip -c '%s' > " - "%s", name_to_load, new_temp_name); - if (system(zz) != 0) - perror(zz); - name_to_load = new_temp_name; - remove_after_load = 1; - } - free(zz); - } - fclose(tmp_f); - } - - byte_order = NO_BYTE_ORDER_OVERRIDE; - - /* - * Load the file: :-) - */ - file_load(m, m->memory, name_to_load, &entrypoint, - m->arch, &gp, &byte_order, &toc); - - if (remove_after_load) { - debug("removing %s\n", name_to_load); - unlink(name_to_load); - } - - if (byte_order != NO_BYTE_ORDER_OVERRIDE) - cpu->byte_order = byte_order; - - cpu->pc = entrypoint; - - switch (m->arch) { - - case ARCH_ALPHA: - /* For position-independent code: */ - cpu->cd.alpha.r[ALPHA_T12] = cpu->pc; - break; - - case ARCH_ARM: - if (cpu->pc & 2) { - fatal("ARM: misaligned pc: TODO\n"); - exit(1); - } - - cpu->pc = (uint32_t)cpu->pc; - - // Lowest bit of PC indicates THUMB mode. - if (cpu->pc & 1) - cpu->cd.arm.cpsr |= ARM_FLAG_T; - break; - - case ARCH_M88K: - if (cpu->pc & 3) { - fatal("M88K: lowest bits of pc set: TODO\n"); - exit(1); - } - cpu->pc &= 0xfffffffc; - break; - - case ARCH_MIPS: - if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL)) - cpu->pc |= 0xffffffff00000000ULL; - - cpu->cd.mips.gpr[MIPS_GPR_GP] = gp; - - if ((cpu->cd.mips.gpr[MIPS_GPR_GP] >> 32) == 0 && - (cpu->cd.mips.gpr[MIPS_GPR_GP] & 0x80000000ULL)) - cpu->cd.mips.gpr[MIPS_GPR_GP] |= - 0xffffffff00000000ULL; - break; - - case ARCH_PPC: - /* See http://www.linuxbase.org/spec/ELF/ppc64/ - spec/x458.html for more info. */ - cpu->cd.ppc.gpr[2] = toc; - /* TODO */ - if (cpu->cd.ppc.bits == 32) - cpu->pc &= 0xffffffffULL; - break; - - case ARCH_SH: - if (cpu->cd.sh.cpu_type.bits == 32) - cpu->pc &= 0xffffffffULL; - cpu->pc &= ~1; - break; - - default: - fatal("emul_machine_setup(): Internal error: " - "Unimplemented arch %i\n", m->arch); - exit(1); - } - - n_load --; - load_names ++; - } - - if (m->byte_order_override != NO_BYTE_ORDER_OVERRIDE) - cpu->byte_order = m->byte_order_override; - - /* Same byte order and entrypoint for all CPUs: */ - for (i=0; incpus; i++) - if (i != m->bootstrap_cpu) { - m->cpus[i]->byte_order = cpu->byte_order; - m->cpus[i]->pc = cpu->pc; - } - - /* Startup the bootstrap CPU: */ - cpu->running = 1; - - /* ... or pause all CPUs, if start_paused is set: */ - if (m->start_paused) { - for (i=0; incpus; i++) - m->cpus[i]->running = 0; - } - - /* Parse and add breakpoints: */ - add_breakpoints(m); - - /* TODO: This is MIPS-specific! */ - if (m->machine_type == MACHINE_PMAX && - cpu->cd.mips.cpu_type.mmu_model == MMU3K) - add_symbol_name(&m->symbol_context, - 0x9fff0000, 0x10000, "r2k3k_cache", 0, 0); - - symbol_recalc_sizes(&m->symbol_context); - - /* Special hack for ARC/SGI emulation: */ - if ((m->machine_type == MACHINE_ARC || - m->machine_type == MACHINE_SGI) && m->prom_emulation) - add_arc_components(m); - - debug("cpu%i: starting at ", m->bootstrap_cpu); - - switch (m->arch) { - - case ARCH_MIPS: - if (cpu->is_32bit) { - debug("0x%08" PRIx32, (uint32_t) - m->cpus[m->bootstrap_cpu]->pc); - if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0) - debug(" (gp=0x%08" PRIx32")", (uint32_t) - m->cpus[m->bootstrap_cpu]->cd.mips.gpr[ - MIPS_GPR_GP]); - } else { - debug("0x%016" PRIx64, (uint64_t) - m->cpus[m->bootstrap_cpu]->pc); - if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0) - debug(" (gp=0x%016" PRIx64")", (uint64_t) - cpu->cd.mips.gpr[MIPS_GPR_GP]); - } - break; - - default: - if (cpu->is_32bit) - debug("0x%08" PRIx32, (uint32_t) cpu->pc); - else - debug("0x%016" PRIx64, (uint64_t) cpu->pc); - } - debug("\n"); - - debug_indentation(-iadd); -} - - -/* - * emul_dumpinfo(): - * - * Dump info about all machines in an emul. - */ -void emul_dumpinfo(struct emul *e) -{ - int i; - - if (e->net != NULL) - net_dumpinfo(e->net); - - for (i = 0; i < e->n_machines; i++) { - if (e->n_machines > 1) - debug("machine %i: \"%s\"\n", i, e->machines[i]->name); - else - debug("machine:\n"); - - debug_indentation(DEBUG_INDENTATION); - - machine_dumpinfo(e->machines[i]); - - debug_indentation(-DEBUG_INDENTATION); - } -} - - -/* - * emul_simple_init(): - * - * For a normal setup: - * - * o) Initialize a network. - * o) Initialize one machine. - */ -void emul_simple_init(struct emul *emul) -{ - int iadd = DEBUG_INDENTATION; - struct machine *m; - - if (emul->n_machines != 1) { - fprintf(stderr, "emul_simple_init(): n_machines != 1\n"); - exit(1); - } - - m = emul->machines[0]; - - debug("Simple setup...\n"); - debug_indentation(iadd); - - /* Create a simple network: */ - emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY, - NET_DEFAULT_IPV4_MASK, - NET_DEFAULT_IPV4_LEN, - NULL, 0, 0, NULL); - - /* Create the machine: */ - emul_machine_setup(m, extra_argc, extra_argv, 0, NULL); - - debug_indentation(-iadd); -} - - -/* - * emul_create_from_configfile(): - * - * Create an emul struct by reading settings from a configuration file. - */ -struct emul *emul_create_from_configfile(char *fname) -{ - int iadd = DEBUG_INDENTATION; - struct emul *e = emul_new(fname); - - debug("Creating emulation from configfile \"%s\":\n", fname); - debug_indentation(iadd); - - emul_parse_config(e, fname); - - debug_indentation(-iadd); - return e; -} - - -/* - * emul_run(): - * - * o) Set up things needed before running an emulation. - * - * o) Run instructions in all machines. - * - * o) De-initialize things. - */ -void emul_run(struct emul *emul) -{ - int i = 0, j, go = 1, n, anything; - - atexit(fix_console); - - if (emul == NULL) { - fatal("No emulation defined. Aborting.\n"); - return; - } - - if (emul->n_machines == 0) { - fatal("No machine(s) defined. Aborting.\n"); - return; - } - - /* Initialize the interactive debugger: */ - debugger_init(emul); - - /* Run any additional debugger commands before starting: */ - if (emul->n_debugger_cmds > 0) { - if (i == 0) - print_separator_line(); - for (int k = 0; k < emul->n_debugger_cmds; k ++) { - debug("> %s\n", emul->debugger_cmds[k]); - debugger_execute_cmd(emul->debugger_cmds[k], - strlen(emul->debugger_cmds[k])); - } - } - - print_separator_line(); - debug("\n"); - - - /* - * console_init_main() makes sure that the terminal is in a - * reasonable state. - * - * The SIGINT handler is for CTRL-C (enter the interactive debugger). - * - * The SIGCONT handler is invoked whenever the user presses CTRL-Z - * (or sends SIGSTOP) and then continues. It makes sure that the - * terminal is in an expected state. - */ - console_init_main(emul); - - signal(SIGINT, debugger_activate); - signal(SIGCONT, console_sigcont); - - /* Not in verbose mode? Then set quiet_mode. */ - if (!verbose) - quiet_mode = 1; - - - /* Initialize all CPUs in all machines: */ - for (j=0; jn_machines; j++) - cpu_run_init(emul->machines[j]); - - /* TODO: Generalize: */ - if (emul->machines[0]->show_trace_tree) - cpu_functioncall_trace(emul->machines[0]->cpus[0], - emul->machines[0]->cpus[0]->pc); - - /* Start emulated clocks: */ - timer_start(); - - - /* - * MAIN LOOP: - * - * Run all emulations in parallel, running instructions from each - * cpu in each machine. - */ - while (go) { - struct cpu *bootcpu = emul->machines[0]->cpus[ - emul->machines[0]->bootstrap_cpu]; - - go = 0; - - /* Flush X11 and serial console output every now and then: */ - if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) { - x11_check_event(emul); - console_flush(); - bootcpu->ninstrs_flush = bootcpu->ninstrs; - } - - if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) { - bootcpu->ninstrs_since_gettimeofday += - (bootcpu->ninstrs - bootcpu->ninstrs_show); - cpu_show_cycles(emul->machines[0], 0); - bootcpu->ninstrs_show = bootcpu->ninstrs; - } - - if (single_step == ENTER_SINGLE_STEPPING) { - /* TODO: Cleanup! */ - old_instruction_trace = - emul->machines[0]->instruction_trace; - old_quiet_mode = quiet_mode; - old_show_trace_tree = - emul->machines[0]->show_trace_tree; - emul->machines[0]->instruction_trace = 1; - emul->machines[0]->show_trace_tree = 1; - quiet_mode = 0; - single_step = SINGLE_STEPPING; - } - - if (single_step == SINGLE_STEPPING) - debugger(); - - for (j=0; jn_machines; j++) { - anything = machine_run(emul->machines[j]); - if (anything) - go = 1; - } - } - - /* Stop any running timers: */ - timer_stop(); - - /* Deinitialize all CPUs in all machines: */ - for (j=0; jn_machines; j++) - cpu_run_deinit(emul->machines[j]); - - /* force_debugger_at_exit flag set? Then enter the debugger: */ - if (force_debugger_at_exit) { - quiet_mode = 0; - debugger_reset(); - debugger(); - } - - /* Any machine using X11? Then wait before exiting: */ - n = 0; - for (j=0; jn_machines; j++) - if (emul->machines[j]->x11_md.in_use) - n++; - - if (n > 0) { - printf("Press enter to quit.\n"); - while (!console_charavail(MAIN_CONSOLE)) { - x11_check_event(emul); - usleep(10000); - } - console_readchar(MAIN_CONSOLE); - } - - console_deinit_main(); -} - diff -Nru gxemul-0.6.2/src/old_main/emul_parse.cc gxemul-0.7.0+dfsg/src/old_main/emul_parse.cc --- gxemul-0.6.2/src/old_main/emul_parse.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/emul_parse.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,751 +0,0 @@ -/* - * Copyright (C) 2005-2009 Anders Gavare. 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. The name of the author 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. - * - * - * Set up an emulation by parsing a config file. - * - * TODO: REWRITE THIS FROM SCRATCH! :-) - */ - -#include -#include -#include - -#include "diskimage.h" -#include "emul.h" -#include "machine.h" -#include "misc.h" -#include "net.h" - - -#define is_word_char(ch) ( \ - (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || \ - ch == '_' || ch == '$' || (ch >= '0' && ch <= '9') ) - -#define MAX_WORD_LEN 200 - -#define EXPECT_WORD 1 -#define EXPECT_LEFT_PARENTHESIS 2 -#define EXPECT_RIGHT_PARENTHESIS 4 - -static int parenthesis_level = 0; - - -/* - * read_one_word(): - * - * Reads the file f until it has read a complete word. Whitespace is ignored, - * and also any exclamation mark ('!') and anything following an exclamation - * mark on a line. - * - * Used internally by emul_parse_config(). - */ -static void read_one_word(FILE *f, char *buf, int buflen, int *line, - int expect) -{ - int ch; - int done = 0; - int curlen = 0; - int in_word = 0; - - while (!done) { - if (curlen >= buflen - 1) - break; - - ch = fgetc(f); - if (ch == EOF) - break; - - if (in_word) { - if (is_word_char(ch)) { - buf[curlen++] = ch; - if (curlen == buflen - 1) - done = 1; - continue; - } else { - if (ungetc(ch, f) == EOF) { - fatal("ungetc() failed?\n"); - exit(1); - } - break; - } - } - - if (ch == '\n') { - (*line) ++; - continue; - } - - if (ch == '\r') - continue; - - if (ch == '!') { - /* Skip until newline: */ - while (ch != '\n' && ch != EOF) - ch = fgetc(f); - if (ch == '\n') - (*line) ++; - continue; - } - - if (ch == '{') { - int depth = 1; - - /* Skip until '}': */ - while (depth > 0) { - ch = fgetc(f); - if (ch == '\n') - (*line) ++; - if (ch == '{') - depth ++; - if (ch == '}') - depth --; - if (ch == EOF) { - fatal("line %i: unexpected EOF inside" - " a nested comment\n", *line); - exit(1); - } - } - continue; - } - - /* Whitespace? */ - if (ch <= ' ') - continue; - - if (ch == '"' || ch == '\'') { - /* This is a quoted word. */ - int start_ch = ch; - - if (expect & EXPECT_LEFT_PARENTHESIS) { - fatal("unexpected character '%c', line %i\n", - ch, *line); - exit(1); - } - - while (curlen < buflen - 1) { - ch = fgetc(f); - if (ch == '\n') { - fatal("line %i: newline inside" - " quotes?\n", *line); - exit(1); - } - if (ch == EOF) { - fatal("line %i: EOF inside a quoted" - " string?\n", *line); - exit(1); - } - if (ch == start_ch) - break; - buf[curlen++] = ch; - } - break; - } - - if ((expect & EXPECT_WORD) && is_word_char(ch)) { - buf[curlen++] = ch; - in_word = 1; - if (curlen == buflen - 1) - done = 1; - } else { - if ((expect & EXPECT_LEFT_PARENTHESIS) && ch == '(') { - parenthesis_level ++; - buf[curlen++] = ch; - break; - } - if ((expect & EXPECT_RIGHT_PARENTHESIS) && ch == ')') { - parenthesis_level --; - buf[curlen++] = ch; - break; - } - - fatal("unexpected character '%c', line %i\n", - ch, *line); - exit(1); - } - } - - buf[curlen] = '\0'; -} - - -#define PARSESTATE_NONE 0 -#define PARSESTATE_EMUL 1 -#define PARSESTATE_NET 2 -#define PARSESTATE_MACHINE 3 - -static char cur_net_ipv4net[50]; -static char cur_net_ipv4len[50]; -static char cur_net_local_port[10]; -#define MAX_N_REMOTE 20 -#define MAX_REMOTE_LEN 100 -static char *cur_net_remote[MAX_N_REMOTE]; -static int cur_net_n_remote; - -static char cur_machine_name[50]; -static char cur_machine_cpu[50]; -static char cur_machine_type[50]; -static char cur_machine_subtype[50]; -static char cur_machine_bootname[150]; -static char cur_machine_bootarg[250]; -static char cur_machine_slowsi[10]; -static char cur_machine_prom_emulation[10]; -static char cur_machine_use_x11[10]; -static char cur_machine_x11_scaledown[10]; -static char cur_machine_byte_order[20]; -static char cur_machine_random_mem[10]; -static char cur_machine_random_cpu[10]; -static char cur_machine_force_netboot[10]; -static char cur_machine_start_paused[10]; -static char cur_machine_ncpus[10]; -static char cur_machine_n_gfx_cards[10]; -static char cur_machine_serial_nr[10]; -static char cur_machine_emulated_hz[10]; -static char cur_machine_memory[10]; -#define MAX_N_LOAD 15 -#define MAX_LOAD_LEN 2000 -static char *cur_machine_load[MAX_N_LOAD]; -static int cur_machine_n_load; -#define MAX_N_DISK 10 -#define MAX_DISK_LEN 2000 -static char *cur_machine_disk[MAX_N_DISK]; -static int cur_machine_n_disk; -#define MAX_N_DEVICE 20 -#define MAX_DEVICE_LEN 400 -static char *cur_machine_device[MAX_N_DISK]; -static int cur_machine_n_device; -#define MAX_N_X11_DISP 5 -#define MAX_X11_DISP_LEN 1000 -static char *cur_machine_x11_disp[MAX_N_X11_DISP]; -static int cur_machine_n_x11_disp; - -#define WORD(w,var) { \ - if (strcmp(word, w) == 0) { \ - read_one_word(f, word, maxbuflen, \ - line, EXPECT_LEFT_PARENTHESIS); \ - read_one_word(f, var, sizeof(var), \ - line, EXPECT_WORD); \ - read_one_word(f, word, maxbuflen, \ - line, EXPECT_RIGHT_PARENTHESIS); \ - return; \ - } \ - } - -static void parse__machine(struct emul *e, FILE *f, int *in_emul, int *line, - int *parsestate, char *word, size_t maxbuflen); - - -/* - * parse_on_off(): - * - * Returns 1 for "on", "yes", "enable", or "1". - * Returns 0 for "off", "no", "disable", or "0". - * Prints a fatal warning and exit()s for other values. - */ -int parse_on_off(char *s) -{ - if (strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 || - strcasecmp(s, "enable") == 0 || strcasecmp(s, "1") == 0) - return 1; - if (strcasecmp(s, "off") == 0 || strcasecmp(s, "no") == 0 || - strcasecmp(s, "disable") == 0 || strcasecmp(s, "0") == 0) - return 0; - - fprintf(stderr, "parse_on_off(): WARNING: unknown value '%s'\n", s); - - return 0; -} - - -/* - * parse__emul(): - * - * name, net, machine - */ -static void parse__emul(struct emul *e, FILE *f, int *in_emul, int *line, - int *parsestate, char *word, size_t maxbuflen) -{ - if (word[0] == ')') { - *parsestate = PARSESTATE_NONE; - return; - } - - if (strcmp(word, "name") == 0) { - char tmp[200]; - read_one_word(f, word, maxbuflen, - line, EXPECT_LEFT_PARENTHESIS); - read_one_word(f, tmp, sizeof(tmp), line, EXPECT_WORD); - read_one_word(f, word, maxbuflen, - line, EXPECT_RIGHT_PARENTHESIS); - if (e->name != NULL) { - free(e->name); - e->name = NULL; - } - CHECK_ALLOCATION(e->name = strdup(tmp)); - debug("name: \"%s\"\n", e->name); - return; - } - - if (strcmp(word, "net") == 0) { - *parsestate = PARSESTATE_NET; - read_one_word(f, word, maxbuflen, - line, EXPECT_LEFT_PARENTHESIS); - - /* Default net: */ - strlcpy(cur_net_ipv4net, NET_DEFAULT_IPV4_MASK, - sizeof(cur_net_ipv4net)); - snprintf(cur_net_ipv4len, sizeof(cur_net_ipv4len), "%i", - NET_DEFAULT_IPV4_LEN); - strlcpy(cur_net_local_port, "", sizeof(cur_net_local_port)); - cur_net_n_remote = 0; - return; - } - - if (strcmp(word, "machine") == 0) { - *parsestate = PARSESTATE_MACHINE; - read_one_word(f, word, maxbuflen, - line, EXPECT_LEFT_PARENTHESIS); - - /* A "zero state": */ - cur_machine_name[0] = '\0'; - cur_machine_cpu[0] = '\0'; - cur_machine_type[0] = '\0'; - cur_machine_subtype[0] = '\0'; - cur_machine_bootname[0] = '\0'; - cur_machine_bootarg[0] = '\0'; - cur_machine_n_load = 0; - cur_machine_n_disk = 0; - cur_machine_n_device = 0; - cur_machine_n_x11_disp = 0; - cur_machine_slowsi[0] = '\0'; - cur_machine_prom_emulation[0] = '\0'; - cur_machine_use_x11[0] = '\0'; - cur_machine_x11_scaledown[0] = '\0'; - cur_machine_byte_order[0] = '\0'; - cur_machine_random_mem[0] = '\0'; - cur_machine_random_cpu[0] = '\0'; - cur_machine_force_netboot[0] = '\0'; - cur_machine_start_paused[0] = '\0'; - cur_machine_ncpus[0] = '\0'; - cur_machine_n_gfx_cards[0] = '\0'; - cur_machine_serial_nr[0] = '\0'; - cur_machine_emulated_hz[0] = '\0'; - cur_machine_memory[0] = '\0'; - return; - } - - fatal("line %i: not expecting '%s' in an 'emul' section\n", - *line, word); - exit(1); -} - - -/* - * parse__net(): - * - * Simple words: ipv4net, ipv4len, local_port - * - * Complex: add_remote - * - * TODO: more words? for example an option to disable the gateway? that would - * have to be implemented correctly in src/net.c first. - */ -static void parse__net(struct emul *e, FILE *f, int *in_emul, int *line, - int *parsestate, char *word, size_t maxbuflen) -{ - int i; - - if (word[0] == ')') { - /* Finished with the 'net' section. Let's create the net: */ - if (e->net != NULL) { - fatal("line %i: more than one net isn't really " - "supported yet\n", *line); - exit(1); - } - - if (!cur_net_local_port[0]) - strlcpy(cur_net_local_port, "0", - sizeof(cur_net_local_port)); - - e->net = net_init(e, NET_INIT_FLAG_GATEWAY, - cur_net_ipv4net, atoi(cur_net_ipv4len), - cur_net_remote, cur_net_n_remote, - atoi(cur_net_local_port), NULL); - - if (e->net == NULL) { - fatal("line %i: fatal error: could not create" - " the net (?)\n", *line); - exit(1); - } - - for (i=0; i= MAX_N_REMOTE) { - fprintf(stderr, "too many remote networks\n"); - exit(1); - } - - CHECK_ALLOCATION(cur_net_remote[cur_net_n_remote] = - (char *) malloc(MAX_REMOTE_LEN)); - read_one_word(f, cur_net_remote[cur_net_n_remote], - MAX_REMOTE_LEN, line, EXPECT_WORD); - cur_net_n_remote ++; - read_one_word(f, word, maxbuflen, line, - EXPECT_RIGHT_PARENTHESIS); - return; - } - - fatal("line %i: not expecting '%s' in a 'net' section\n", *line, word); - exit(1); -} - - -/* - * parse__machine(): - */ -static void parse__machine(struct emul *e, FILE *f, int *in_emul, int *line, - int *parsestate, char *word, size_t maxbuflen) -{ - int r, i; - - if (word[0] == ')') { - /* Finished with the 'machine' section. */ - struct machine *m; - - if (!cur_machine_name[0]) - strlcpy(cur_machine_name, "no_name", - sizeof(cur_machine_name)); - - m = emul_add_machine(e, cur_machine_name); - - r = machine_name_to_type(cur_machine_type, cur_machine_subtype, - &m->machine_type, &m->machine_subtype, &m->arch); - if (!r) - exit(1); - - if (cur_machine_cpu[0]) - CHECK_ALLOCATION(m->cpu_name = strdup(cur_machine_cpu)); - - if (!cur_machine_use_x11[0]) - strlcpy(cur_machine_use_x11, "no", - sizeof(cur_machine_use_x11)); - m->x11_md.in_use = parse_on_off(cur_machine_use_x11); - - if (!cur_machine_slowsi[0]) - strlcpy(cur_machine_slowsi, "no", - sizeof(cur_machine_slowsi)); - m->slow_serial_interrupts_hack_for_linux = - parse_on_off(cur_machine_slowsi); - - if (!cur_machine_prom_emulation[0]) - strlcpy(cur_machine_prom_emulation, "yes", - sizeof(cur_machine_prom_emulation)); - m->prom_emulation = parse_on_off(cur_machine_prom_emulation); - - if (!cur_machine_random_mem[0]) - strlcpy(cur_machine_random_mem, "no", - sizeof(cur_machine_random_mem)); - m->random_mem_contents = - parse_on_off(cur_machine_random_mem); - - if (!cur_machine_random_cpu[0]) - strlcpy(cur_machine_random_cpu, "no", - sizeof(cur_machine_random_cpu)); - m->use_random_bootstrap_cpu = - parse_on_off(cur_machine_random_cpu); - - m->byte_order_override = NO_BYTE_ORDER_OVERRIDE; - if (cur_machine_byte_order[0]) { - if (strncasecmp(cur_machine_byte_order, "big", 3) == 0) - m->byte_order_override = EMUL_BIG_ENDIAN; - else if (strncasecmp(cur_machine_byte_order, "little", - 6) == 0) - m->byte_order_override = EMUL_LITTLE_ENDIAN; - else { - fatal("Byte order must be big-endian or" - " little-endian\n"); - exit(1); - } - } - - if (!cur_machine_force_netboot[0]) - strlcpy(cur_machine_force_netboot, "no", - sizeof(cur_machine_force_netboot)); - m->force_netboot = parse_on_off(cur_machine_force_netboot); - - if (!cur_machine_start_paused[0]) - strlcpy(cur_machine_start_paused, "no", - sizeof(cur_machine_start_paused)); - m->start_paused = parse_on_off(cur_machine_start_paused); - - /* NOTE: Default nr of CPUs is 0: */ - if (!cur_machine_ncpus[0]) - strlcpy(cur_machine_ncpus, "0", - sizeof(cur_machine_ncpus)); - m->ncpus = atoi(cur_machine_ncpus); - - if (cur_machine_n_gfx_cards[0]) - m->n_gfx_cards = atoi(cur_machine_n_gfx_cards); - - if (cur_machine_serial_nr[0]) { - m->serial_nr = atoi(cur_machine_serial_nr); - e->next_serial_nr = m->serial_nr+1; - } - - if (cur_machine_emulated_hz[0]) { - m->emulated_hz = mystrtoull(cur_machine_emulated_hz, - NULL, 0); - } - - /* NOTE: Default nr of CPUs is 0: */ - if (!cur_machine_memory[0]) - strlcpy(cur_machine_memory, "0", - sizeof(cur_machine_memory)); - m->physical_ram_in_mb = atoi(cur_machine_memory); - - if (!cur_machine_x11_scaledown[0]) - m->x11_md.scaledown = 1; - else { - m->x11_md.scaledown = atoi(cur_machine_x11_scaledown); - if (m->x11_md.scaledown < 0) { - m->x11_md.scaleup = 0 - m->x11_md.scaledown; - m->x11_md.scaledown = 1; - } - if (m->x11_md.scaledown < 1) { - fprintf(stderr, "Invalid scaledown value" - " (%i)\n", m->x11_md.scaledown); - exit(1); - } - } - - for (i=0; iboot_kernel_filename = strdup(cur_machine_bootname); - - if (cur_machine_bootarg[0]) - m->boot_string_argument = strdup(cur_machine_bootarg); - - for (i=0; ix11_md.n_display_names ++; - CHECK_ALLOCATION(m->x11_md.display_names = (char **) realloc( - m->x11_md.display_names, m->x11_md.n_display_names - * sizeof(char *))); - CHECK_ALLOCATION(m->x11_md.display_names[ - m->x11_md.n_display_names-1] = - strdup(cur_machine_x11_disp[i])); - free(cur_machine_x11_disp[i]); - cur_machine_x11_disp[i] = NULL; - } - - emul_machine_setup(m, - cur_machine_n_load, cur_machine_load, - cur_machine_n_device, cur_machine_device); - - for (i=0; i= MAX_N_LOAD) { - fprintf(stderr, "too many loads\n"); - exit(1); - } - CHECK_ALLOCATION(cur_machine_load[cur_machine_n_load] = - (char*) malloc(MAX_LOAD_LEN)); - read_one_word(f, cur_machine_load[cur_machine_n_load], - MAX_LOAD_LEN, line, EXPECT_WORD); - cur_machine_n_load ++; - read_one_word(f, word, maxbuflen, - line, EXPECT_RIGHT_PARENTHESIS); - return; - } - - if (strcmp(word, "disk") == 0) { - read_one_word(f, word, maxbuflen, - line, EXPECT_LEFT_PARENTHESIS); - if (cur_machine_n_disk >= MAX_N_DISK) { - fprintf(stderr, "too many disks\n"); - exit(1); - } - CHECK_ALLOCATION(cur_machine_disk[cur_machine_n_disk] = - (char*) malloc(MAX_DISK_LEN)); - read_one_word(f, cur_machine_disk[cur_machine_n_disk], - MAX_DISK_LEN, line, EXPECT_WORD); - cur_machine_n_disk ++; - read_one_word(f, word, maxbuflen, - line, EXPECT_RIGHT_PARENTHESIS); - return; - } - - if (strcmp(word, "device") == 0) { - read_one_word(f, word, maxbuflen, - line, EXPECT_LEFT_PARENTHESIS); - if (cur_machine_n_device >= MAX_N_DEVICE) { - fprintf(stderr, "too many devices\n"); - exit(1); - } - CHECK_ALLOCATION(cur_machine_device[cur_machine_n_device] = - (char*) malloc(MAX_DEVICE_LEN)); - read_one_word(f, cur_machine_device[cur_machine_n_device], - MAX_DEVICE_LEN, line, EXPECT_WORD); - cur_machine_n_device ++; - read_one_word(f, word, maxbuflen, - line, EXPECT_RIGHT_PARENTHESIS); - return; - } - - if (strcmp(word, "add_x11_display") == 0) { - read_one_word(f, word, maxbuflen, - line, EXPECT_LEFT_PARENTHESIS); - if (cur_machine_n_x11_disp >= MAX_N_X11_DISP) { - fprintf(stderr, "too many x11 displays\n"); - exit(1); - } - CHECK_ALLOCATION(cur_machine_x11_disp[cur_machine_n_x11_disp] = - (char*) malloc(MAX_X11_DISP_LEN)); - read_one_word(f, cur_machine_x11_disp[cur_machine_n_x11_disp], - MAX_X11_DISP_LEN, line, EXPECT_WORD); - cur_machine_n_x11_disp ++; - read_one_word(f, word, maxbuflen, - line, EXPECT_RIGHT_PARENTHESIS); - return; - } - - fatal("line %i: not expecting '%s' in a 'machine' section\n", - *line, word); - exit(1); -} - - -/* - * emul_parse_config(): - * - * Set up an emulation by parsing a config file. - */ -void emul_parse_config(struct emul *e, char *fname) -{ - FILE *f = fopen(fname, "r"); - char word[MAX_WORD_LEN]; - int in_emul = 0; - int line = 1; - int parsestate = PARSESTATE_EMUL; - - /* debug("emul_parse_config()\n"); */ - if (f == NULL) { - perror(fname); - exit(1); - } - - while (!feof(f)) { - read_one_word(f, word, sizeof(word), &line, - EXPECT_WORD | EXPECT_RIGHT_PARENTHESIS); - if (!word[0]) - break; - - /* debug("word = '%s'\n", word); */ - - switch (parsestate) { - case PARSESTATE_EMUL: - parse__emul(e, f, &in_emul, &line, &parsestate, - word, sizeof(word)); - break; - case PARSESTATE_NET: - parse__net(e, f, &in_emul, &line, &parsestate, - word, sizeof(word)); - break; - case PARSESTATE_MACHINE: - parse__machine(e, f, &in_emul, &line, &parsestate, - word, sizeof(word)); - break; - case PARSESTATE_NONE: - break; - default: - fatal("INTERNAL ERROR in emul_parse.c (" - "parsestate %i is not imlemented yet?)\n", - parsestate); - exit(1); - } - } - - if (parenthesis_level != 0) { - fatal("EOF but not enough right parentheses?\n"); - exit(1); - } - - fclose(f); -} - diff -Nru gxemul-0.6.2/src/old_main/float_emul.cc gxemul-0.7.0+dfsg/src/old_main/float_emul.cc --- gxemul-0.6.2/src/old_main/float_emul.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/float_emul.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2004-2018 Anders Gavare. 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. The name of the author 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. - * - * - * Floating point emulation routines. - */ - -#include -#include -#include -#include - -#include "float_emul.h" -#include "misc.h" - - -/* #define IEEE_DEBUG */ - - -/* - * ieee_interpret_float_value(): - * - * Interprets a float value from binary IEEE format into an ieee_float_value - * struct. - */ -void ieee_interpret_float_value(uint64_t x, struct ieee_float_value *fvp, - int fmt) -{ - memset(fvp, 0, sizeof(struct ieee_float_value)); - -#if 0 - // HACK: Use the host's float/double representation: - switch (fmt) { - case IEEE_FMT_S: - { - uint32_t x2 = x; - void* p = (void*) &x2; - float *pf = (float*) p; - fvp->f = *pf; - } - break; - - case IEEE_FMT_D: - { - void* p = (void*) &x; - double *pf = (double*) p; - fvp->f = *pf; - } - break; - - case IEEE_FMT_W: - case IEEE_FMT_L: - { - fvp->f = x; - } - break; - - default:fatal("ieee_interpret_float_value(): " - "unimplemented format %i\n", fmt); - } - - fvp->nan = isnan(fvp->f); -#else - int n_frac = 0, n_exp = 0; - int i, nan, sign = 0, exponent; - double fraction; - - /* n_frac and n_exp: */ - switch (fmt) { - case IEEE_FMT_S: n_frac = 23; n_exp = 8; break; - case IEEE_FMT_W: n_frac = 31; n_exp = 0; break; - case IEEE_FMT_D: n_frac = 52; n_exp = 11; break; - case IEEE_FMT_L: n_frac = 63; n_exp = 0; break; - default:fatal("ieee_interpret_float_value(): " - "unimplemented format %i\n", fmt); - } - - /* Get the Exponent: */ - exponent = 0; - switch (fmt) { - case IEEE_FMT_W: - x &= 0xffffffffULL; - case IEEE_FMT_L: - break; - case IEEE_FMT_S: - x &= 0xffffffffULL; - case IEEE_FMT_D: - exponent = (x >> n_frac) & ((1 << n_exp) - 1); - exponent -= (1 << (n_exp-1)) - 1; - break; - default:fatal("ieee_interpret_float_value(): unimplemented " - "format %i\n", fmt); - } - - /* Is this a Not-A-Number? */ - nan = 0; - switch (fmt) { - case IEEE_FMT_S: - sign = (x >> 31) & 1; - if ((x & ~0x80000000ULL) == 0x7f800000ULL) { - fvp->f = 1.0 / 0.0; - goto zero_or_no_reasonable_result; - } - if ((x & 0x7f800000ULL) == 0x7f800000ULL) - nan = 1; - break; - case IEEE_FMT_D: - sign = (x >> 63) & 1; - if ((x & ~0x8000000000000000ULL) == 0x7ff0000000000000ULL) { - fvp->f = 1.0 / 0.0; - goto zero_or_no_reasonable_result; - } - if ((x & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL) - nan = 1; - break; - } - - if (nan) { - fvp->f = NAN; - goto no_reasonable_result; - } - - /* Calculate the fraction: */ - fraction = 0.0; - - switch (fmt) { - - case IEEE_FMT_W: - { - int32_t r_int = x; - fraction = r_int; - } - break; - - case IEEE_FMT_L: - { - int64_t r_int = x; - fraction = r_int; - } - break; - - case IEEE_FMT_S: - case IEEE_FMT_D: - if (x == 0 || - (fmt == IEEE_FMT_D && x == 0x8000000000000000ULL) || - (fmt == IEEE_FMT_S && x == 0x80000000ULL)) { - fvp->f = 0.0; - goto zero_or_no_reasonable_result; - } - - fraction = 0.0; - for (i=0; i> i) & 1; - fraction /= 2.0; - if (bit) - fraction += 1.0; - } - - /* Add implicit bit 0: */ - fraction = (fraction / 2.0) + 1.0; - break; - - default:fatal("ieee_interpret_float_value(): " - "unimplemented format %i\n", fmt); - } - - /* form the value: */ - fvp->f = fraction; - -#ifdef IEEE_DEBUG - fatal("{ ieee: x=%016"PRIx64" => sign=%i exponent=%i frac=%f ", - (uint64_t) x, sign, exponent, fraction); -#endif - - /* TODO: this is awful for exponents of large magnitude. */ - if (exponent > 0) { - /* - * NOTE / TODO: - * - * This is an ulgy workaround on Alpha, where it seems that - * multiplying by 2, 1024 times causes a floating point - * exception. (Triggered by running for example NetBSD/pmax - * 2.0 emulated on an Alpha host.) - */ - if (exponent == 1024) - exponent = 1023; - - while (exponent-- > 0) - fvp->f *= 2.0; - } else if (exponent < 0) { - while (exponent++ < 0) - fvp->f /= 2.0; - } - -zero_or_no_reasonable_result: - if (sign) - fvp->f = -fvp->f; - -no_reasonable_result: - fvp->nan = nan; - -#ifdef IEEE_DEBUG - fatal("nan=%i (f=%f) }\n", nan, fvp->f); -#endif - -#endif -} - - -/* - * ieee_store_float_value(): - * - * Generates a 64-bit IEEE-formated value in a specific format. - */ -uint64_t ieee_store_float_value(double nf, int fmt) -{ - int n_frac = 0, n_exp = 0, signofs = 0, i, exponent; - uint64_t r = 0, r2; - int64_t r3; - - /* n_frac and n_exp: */ - switch (fmt) { - case IEEE_FMT_S: n_frac = 23; n_exp = 8; signofs = 31; break; - case IEEE_FMT_W: n_frac = 31; n_exp = 0; signofs = 31; break; - case IEEE_FMT_D: n_frac = 52; n_exp = 11; signofs = 63; break; - case IEEE_FMT_L: n_frac = 63; n_exp = 0; signofs = 63; break; - default:fatal("ieee_store_float_value(): unimplemented format" - " %i\n", fmt); - } - - switch (fmt) { - case IEEE_FMT_W: - case IEEE_FMT_L: - /* - * This causes an implicit conversion of double to integer. - * If nf < 0.0, then r2 will begin with a sequence of binary - * 1's, which is ok. - */ - r3 = (int64_t) nf; - r2 = r3; - r |= r2; - break; - case IEEE_FMT_S: - case IEEE_FMT_D: - /* sign bit: */ - if (signbit(nf)) { - r |= ((uint64_t)1 << signofs); - } - - // printf("fpclassify(nf) = %i\n", fpclassify(nf)); - switch (fpclassify(nf)) { - case FP_INFINITE: - if (fmt == IEEE_FMT_D) - r |= 0x7ff0000000000000ULL; - else - r |= 0x7f800000ULL; - break; - case FP_NAN: - if (fmt == IEEE_FMT_D) - r |= 0x7fffffffffffffffULL; - else - r |= 0x7fffffffULL; - break; - case FP_NORMAL: - if (signbit(nf)) - nf = -nf; - - /* - * How to convert back from double to exponent + fraction: - * The fraction should be 1.xxx, that is - * 1.0 <= fraction < 2.0 - * - * This method is very slow but should work: - * (TODO: Fix the performance problem!) - */ - exponent = 0; - while (nf < 1.0 && exponent > -1023) { - nf *= 2.0; - exponent --; - } - while (nf >= 2.0 && exponent < 1023) { - nf /= 2.0; - exponent ++; - } - - /* Here: 1.0 <= nf < 2.0 */ - nf -= 1.0; /* remove implicit first bit */ - for (i=n_frac-1; i>=0; i--) { - nf *= 2.0; - if (nf >= 1.0) { - r |= ((uint64_t)1 << i); - nf -= 1.0; - } - } - - /* Insert the exponent into the resulting word: */ - /* (First bias, then make sure it's within range) */ - exponent += (((uint64_t)1 << (n_exp-1)) - 1); - if (exponent < 0) - exponent = 0; - if (exponent >= ((int64_t)1 << n_exp)) - exponent = ((int64_t)1 << n_exp) - 1; - r |= (uint64_t)exponent << n_frac; - - /* Special case for 0.0: */ - if (exponent == 0) - r = 0; - break; - case FP_SUBNORMAL: - // TODO - break; - case FP_ZERO: - // r already has zeros in the lowest bits. Done. - break; - } - break; - default:/* TODO */ - fatal("ieee_store_float_value(): unimplemented format %i\n", - fmt); - } - - if (fmt == IEEE_FMT_S || fmt == IEEE_FMT_W) - r = (uint32_t) r; - - return r; -} - diff -Nru gxemul-0.6.2/src/old_main/interrupt.cc gxemul-0.7.0+dfsg/src/old_main/interrupt.cc --- gxemul-0.6.2/src/old_main/interrupt.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/interrupt.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2006-2019 Anders Gavare. 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. The name of the author 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. - * - * - * The interrupt subsystem. - * - * Interrupts have a "path", e.g. "machine[0].cpu.5". A device which - * wishes to cause this interrupt needs to connect to it. - * - * The possible interrupt paths are registered by CPUs, interrupt controllers, - * etc., that have a way of receiving interrupt requests. The physical - * version of an interrupt path is usually a "pin" on the CPU, or similar. - * - * Once connected, the interrupt can be asserted or deasserted. - * - * For examples on how it is used, see the various devices in src/devices/. - */ - -#include -#include -#include - -#include "interrupt.h" -#include "misc.h" - - -/* #define INTERRUPT_DEBUG */ - - -struct interrupt_handler { - struct interrupt templ; - int nr_of_exclusive_users; - int nr_of_nonexclusive_users; -}; - - -static int nr_of_interrupt_handlers = 0; -static struct interrupt_handler *interrupt_handlers = NULL; - - -/* - * Dummy interrupt assert/deassert for "no interrupt" interrupts: - */ -static void no_interrupt_assert(struct interrupt *i) { } -static void no_interrupt_deassert(struct interrupt *i) { } - - -/* - * interrupt_handler_register(): - * - * Add an interrupt handler to the interrupt subsystem. The template - * needs to have all members set. - * - * Name is of the form "machine[0].cpu[0].irq[3].isa[14]" etc. - * - * If there already is a handler with this name, the emulator aborts. - */ -void interrupt_handler_register(struct interrupt *templ) -{ - int i; - -#ifdef INTERRUPT_DEBUG - printf("interrupt_handler_register(\"%s\")\n", templ->name); -#endif - - /* See if the name is already registered: */ - for (i=0; iname, - interrupt_handlers[i].templ.name) != 0) - continue; - - fatal("\ninterrupt_handler_register(): An interrupt handler" - " using the name '%s' is already registered.\n", - templ->name); - exit(1); - } - - nr_of_interrupt_handlers ++; - CHECK_ALLOCATION(interrupt_handlers = - (struct interrupt_handler *) realloc(interrupt_handlers, - nr_of_interrupt_handlers * sizeof(struct interrupt_handler))); - - interrupt_handlers[nr_of_interrupt_handlers-1].templ = *templ; - CHECK_ALLOCATION(interrupt_handlers[nr_of_interrupt_handlers-1]. - templ.name = strdup(templ->name)); -} - - -/* - * interrupt_handler_remove(): - * - * Remove an interrupt handler from the interrupt subsystem. If there are - * still connected users of this interrupt, then an error message is printed - * and the emulator aborts. - */ -void interrupt_handler_remove(const char *name) -{ - int i; - -#ifdef INTERRUPT_DEBUG - printf("interrupt_handler_remove(\"%s\")\n", name); -#endif - - for (i=0; i 0 || - interrupt_handlers[i].nr_of_nonexclusive_users > 0) { - fatal("interrupt_handler_remove(): Attempt to " - "remove interrupt handler '%s' which has %i " - "exclusive and %i non-exclusive users. Aborting.\n", - name, interrupt_handlers[i].nr_of_exclusive_users, - interrupt_handlers[i].nr_of_nonexclusive_users); - exit(1); - } - - if (i != nr_of_interrupt_handlers-1) - memcpy(&interrupt_handlers[i], - &interrupt_handlers[i + 1], - nr_of_interrupt_handlers - i - 1); - - nr_of_interrupt_handlers --; - - return; - } - - fatal("interrupt_handler_remove(): '%s' not found? Aborting.\n", name); - exit(1); -} - - -/* - * interrupt_handler_lookup(): - * - * Scans the list of registered interrupt handlers for a given name. If the - * name is found, the template is filled with valid data, and 1 is returned. - * If the name is not found, 0 is returned. - */ -int interrupt_handler_lookup(const char *name, struct interrupt *templ) -{ - int i; - -#ifdef INTERRUPT_DEBUG - printf("interrupt_handler_lookup(\"%s\")\n", name); -#endif - - if (name[0] == '\0') { - /* No interrupt: */ - memset(templ, 0, sizeof(struct interrupt)); - templ->interrupt_assert = no_interrupt_assert; - templ->interrupt_deassert = no_interrupt_deassert; - } - - for (i=0; i= nr_of_interrupt_handlers) { - printf("interrupt_handler_lookup(\"%s\") failed.\n", name); - - printf("Available handler paths are:\n"); - for (i=0; iname); -#endif - - if (in->name == NULL || in->name[0] == '\0') - return; - - for (i=0; iname, interrupt_handlers[i].templ.name) != 0) - continue; - - if (exclusive) { - interrupt_handlers[i].nr_of_exclusive_users ++; - if (interrupt_handlers[i].nr_of_exclusive_users > 1) { - fatal("Fatal error in interrupt_connect(): " - "more than 1 exclusive user. Dumping " - "core for backtrace.\n"); - abort(); - } - } else { - interrupt_handlers[i].nr_of_nonexclusive_users ++; - } - - return; - } - - fatal("Internal error in interrupt_connect(): name '%s' not " - "found? Dumping core for debugging.\n", in->name); - abort(); -} - - -/* - * interrupt_disconnect(): - * - * Decreases the exclusive or nonexclusive nr or users of an interrupt. - */ -void interrupt_disconnect(struct interrupt *in, int exclusive) -{ - int i; - - if (in->name == NULL || in->name[0] == '\0') - return; - - for (i=0; iname, interrupt_handlers[i].templ.name) != 0) - continue; - - if (exclusive) { - interrupt_handlers[i].nr_of_exclusive_users --; - if (interrupt_handlers[i].nr_of_exclusive_users < 0) { - fatal("Fatal error in interrupt_disconnect():" - "nr of exclusive users < 0?\n"); - exit(1); - } - } else { - interrupt_handlers[i].nr_of_nonexclusive_users --; - if (interrupt_handlers[i].nr_of_nonexclusive_users<0) { - fatal("Fatal error in interrupt_disconnect():" - "nr of non-exclusive users < 0?\n"); - exit(1); - } - } - - return; - } - - fatal("Internal error in interrupt_disconnect(): name '%s' not " - "found?\n", in->name); - exit(1); -} - - diff -Nru gxemul-0.6.2/src/old_main/main.cc gxemul-0.7.0+dfsg/src/old_main/main.cc --- gxemul-0.6.2/src/old_main/main.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/main.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,924 +0,0 @@ -/* - * Copyright (C) 2003-2019 Anders Gavare. 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. The name of the author 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. - * - * - * GXemul's main entry point. - */ - -#include -#include -#include -#include -#include -#include - -#include "ComponentFactory.h" -#include "console.h" -#include "cpu.h" -#include "debugger.h" -#include "device.h" -#include "diskimage.h" -#include "emul.h" -#include "GXemul.h" -#include "machine.h" -#include "misc.h" -#include "settings.h" -#include "timer.h" -#include "UnitTest.h" - - -extern int single_step; -extern int force_debugger_at_exit; - -extern int optind; -extern char *optarg; - -struct settings *global_settings; - -int extra_argc; -char **extra_argv; -char *progname; - -size_t dyntrans_cache_size = DEFAULT_DYNTRANS_CACHE_SIZE; -static int skip_srandom_call = 0; - - -/***************************************************************************** - * - * NOTE: debug(), fatal(), and debug_indentation() are not re-entrant. - * The global variable quiet_mode can be used to suppress the output - * of debug(), but not the output of fatal(). - * - *****************************************************************************/ - -int verbose = 0; -int quiet_mode = 0; - -static int debug_indent = 0; -static int debug_currently_at_start_of_line = 1; - - -/* - * va_debug(): - * - * Used internally by debug() and fatal(). - */ -static void va_debug(va_list argp, const char *fmt) -{ - char buf[DEBUG_BUFSIZE + 1]; - char *s; - int i; - - buf[0] = buf[DEBUG_BUFSIZE] = 0; - vsnprintf(buf, DEBUG_BUFSIZE, fmt, argp); - - s = buf; - while (*s) { - if (debug_currently_at_start_of_line) { - for (i=0; i 0) { - cerr << "Having memory leaks counts as failure to run the tests!\n"; - exit(1); - } -#endif - - exit(result); - } - break; - default: - fprintf(stderr, "internal_w(): UNIMPLEMENTED arg = '%s'\n", - arg); - } -} - - -/*****************************************************************************/ - - -/* - * usage(): - * - * Prints program usage to stdout. - */ -static void usage(int longusage) -{ - - printf("GXemul " VERSION" " COPYRIGHT_MSG"\n" SECONDARY_MSG); - printf("Read the source code and/or documentation for other Copyright messages.\n"); - - printf("\nUsage: %s [machine, other, and general options] [file [...]]\n", progname); - printf(" or %s [general options] @configfile\n", progname); - - if (!longusage) { - printf("\nRun %s -h for help on command line options.\n", progname); - return; - } - - printf("\nMachine selection options:\n"); - printf(" -E t try to emulate machine type t. (Use -H to get " - "a list of types.)\n"); - printf(" -e st try to emulate machine subtype st. (Use this " - "with -E.)\n"); - - printf("\nOther options:\n"); - printf(" -C x try to emulate a specific CPU. (Use -H to get a " - "list of types.)\n"); - printf(" -d fname add fname as a disk image. You can add \"xxx:\"" - " as a prefix\n"); - printf(" where xxx is one or more of the following:\n"); - printf(" b specifies that this is the boot" - " device\n"); - printf(" c CD-ROM\n"); - printf(" d DISK\n"); - printf(" f FLOPPY\n"); - printf(" gH;S; set geometry to H heads and S" - " sectors-per-track\n"); - printf(" i IDE\n"); - printf(" oOFS; set base offset to OFS (for ISO9660" - " filesystems)\n"); - printf(" r read-only (don't allow changes to the" - " file)\n"); - printf(" s SCSI\n"); - printf(" t tape\n"); - printf(" V add an overlay\n"); - printf(" 0-7 force a specific ID\n"); - printf(" -I hz set the main cpu frequency to hz (not used by " - "all combinations\n of machines and guest OSes)\n"); - printf(" -i display each instruction as it is executed\n"); - printf(" -J disable dyntrans instruction combinations\n"); - printf(" -j name set the name of the kernel; for DECstation " - "emulation, this passes\n the name to the bootloader," - " for example:\n"); - printf(" -j netbsd (NetBSD/pmax) " - "-j bsd (OpenBSD/pmax)\n"); - printf(" -j vmsprite (Sprite/pmax) " - "-j vmunix (Ultrix/RISC)\n"); - printf(" For other emulation modes, if the boot disk is an" - " ISO9660\n filesystem, -j sets the name of the" - " kernel to load.\n"); - printf(" -M m emulate m MBs of physical RAM\n"); - printf(" -N display nr of instructions/second average, at" - " regular intervals\n"); - printf(" -n nr set nr of CPUs (for SMP experiments)\n"); - printf(" -O force netboot (tftp instead of disk), even when" - " a disk image is\n" - " present (for DECstation, SGI, and ARC emulation)\n"); - printf(" -o arg set the boot argument, for DEC, ARC, or SGI" - " emulation\n"); - printf(" (default arg for DEC is -a, for ARC/SGI -aN)\n"); - printf(" -p pc add a breakpoint (remember to use the '0x' " - "prefix for hex!)\n"); - printf(" -Q no built-in PROM emulation (use this for " - "running ROM images)\n"); - printf(" -R use random bootstrap cpu, instead of nr 0\n"); - printf(" -r register dumps before every instruction\n"); - printf(" -S initialize emulated RAM to random bytes, " - "instead of zeroes\n"); - printf(" -s f:name write statistics to file 'name', " - "f is one or more of the following:\n"); - printf(" v virtual program counter\n"); - printf(" p physical equivalent of program counter\n"); - printf(" i internal ic->f representation of " - "the program counter\n"); - printf(" and optionally:\n"); - printf(" d disable statistics gathering at " - "startup\n"); - printf(" o overwrite instead of append\n"); - printf(" -T halt on non-existant memory accesses\n"); - printf(" -t show function trace tree\n"); - printf(" -U enable slow_serial_interrupts_hack_for_linux\n"); -#ifdef WITH_X11 - printf(" -X use X11\n"); - printf(" -x open up new xterms for emulated serial ports " - "(default is on when\n using configuration files or" - " when X11 is used, off otherwise)\n"); - printf(" -Y n scale down framebuffer windows by n x n times\n"); -#endif /* WITH_X11 */ - printf(" -Z n set nr of graphics cards, for emulating a " - "dual-head or tripple-head\n" - " environment (only for DECstation emulation)\n"); - printf(" -z disp add disp as an X11 display to use for " - "framebuffers\n"); - - printf("\nGeneral options:\n"); - printf(" -c cmd add cmd as a command to run before starting " - "the simulation\n"); - printf(" -D skip the srandom call at startup\n"); - printf(" -H display a list of possible CPU and " - "machine types\n"); - printf(" -h display this help message\n"); - printf(" -k n set dyntrans translation caches to n MB (default" - " size is %i MB)\n", DEFAULT_DYNTRANS_CACHE_SIZE / 1048576); - printf(" -K force the debugger to be entered at the end " - "of a simulation\n"); - printf(" -q quiet mode (don't print startup messages)\n"); - printf(" -V start up in the single-step debugger, paused\n"); - printf(" -v increase debug message verbosity\n"); - printf("\n"); - printf("If you are selecting a machine type to emulate directly " - "on the command line,\nthen you must specify one or more names" - " of files that you wish to load into\n" - "memory. Supported formats are: ELF a.out ecoff srec syms raw\n" - "where syms is the text produced by running 'nm' (or 'nm -S') " - "on a binary.\n" - "To load a raw binary into memory, add \"address:\" in front " - "of the filename,\n" - "or \"address:skiplen:\" or \"address:skiplen:initialpc:\".\n" - "\nExamples:\n" - " 0xbfc00000:rom.bin for a raw ROM image\n" - " 0xbfc00000:0x100:rom.bin for an image with " - "0x100 bytes header\n" - " 0xbfc00000:0x100:0xbfc00884:rom.bin " - "start with pc=0xbfc00884\n\n"); - - printf("\n\"New framework\" options (experimental):\n"); - printf("\nUsage: %s [options] -e name [additional components and files [...]]\n", progname); - printf(" or %s [options] configfile\n", progname); - printf(" or %s -H\n", progname); - printf(" or %s -V\n", progname); - printf("\n"); - printf(" -B Enable snapshotting (reverse stepping support).\n"); - printf(" -H Display a list of available machine templates.\n"); - printf(" -e name Start with a machine based on template 'name'.\n"); - printf(" -q Quiet mode (suppress debug messages).\n"); - printf(" -V Start up in interactive debugging mode, paused.\n"); - printf("\n"); -} - - -/* - * get_cmd_args(): - * - * Reads command line arguments. - */ -int get_cmd_args(int argc, char *argv[], struct emul *emul, - char ***diskimagesp, int *n_diskimagesp) -{ - int ch, res, using_switch_d = 0, using_switch_Z = 0; - int using_switch_e = 0, using_switch_E = 0; - bool using_switch_B = false; - char *type = NULL, *subtype = NULL; - int n_cpus_set = 0; - int msopts = 0; /* Machine-specific options used */ - struct machine *m = emul_add_machine(emul, NULL); - - const char *opts = - "BC:c:Dd:E:e:HhI:iJj:k:KM:Nn:Oo:p:QqRrSs:TtUVvW:" -#ifdef WITH_X11 - "XxY:" -#endif - "Z:z:"; - - while ((ch = getopt(argc, argv, opts)) != -1) { - switch (ch) { - case 'B': - using_switch_B = true; - break; - case 'C': - CHECK_ALLOCATION(m->cpu_name = strdup(optarg)); - msopts = 1; - break; - case 'c': - emul->n_debugger_cmds ++; - CHECK_ALLOCATION(emul->debugger_cmds = (char **) - realloc(emul->debugger_cmds, - emul->n_debugger_cmds * sizeof(char *))); - CHECK_ALLOCATION(emul->debugger_cmds[emul-> - n_debugger_cmds-1] = strdup(optarg)); - break; - case 'D': - skip_srandom_call = 1; - break; - case 'd': - /* diskimage_add() is called further down */ - (*n_diskimagesp) ++; - CHECK_ALLOCATION( (*diskimagesp) = (char **) - realloc(*diskimagesp, - sizeof(char *) * (*n_diskimagesp)) ); - CHECK_ALLOCATION( (*diskimagesp)[(*n_diskimagesp) - 1] = - strdup(optarg) ); - using_switch_d = 1; - msopts = 1; - break; - case 'E': - if (using_switch_E ++ > 0) { - fprintf(stderr, "-E already used.\n"); - exit(1); - } - type = optarg; - msopts = 1; - break; - case 'e': - if (using_switch_e ++ > 0) { - fprintf(stderr, "-e already used.\n"); - exit(1); - } - subtype = optarg; - msopts = 1; - break; - case 'H': - GXemul::ListTemplates(); - printf("--------------------------------------------------------------------------\n\n"); - printf("The following applies to the LEGACY modes only:\n\n"); - machine_list_available_types_and_cpus(); - exit(1); - case 'h': - usage(1); - exit(1); - case 'I': - m->emulated_hz = atoi(optarg); - msopts = 1; - break; - case 'i': - m->instruction_trace = 1; - msopts = 1; - break; - case 'J': - m->allow_instruction_combinations = 0; - msopts = 1; - break; - case 'j': - CHECK_ALLOCATION(m->boot_kernel_filename = - strdup(optarg)); - msopts = 1; - break; - case 'k': - dyntrans_cache_size = atoi(optarg) * 1048576; - if (dyntrans_cache_size < 1) { - fprintf(stderr, "The dyntrans cache size must" - " be at least 1 MB.\n"); - exit(1); - } - break; - case 'K': - force_debugger_at_exit = 1; - break; - case 'M': - m->physical_ram_in_mb = atoi(optarg); - msopts = 1; - break; - case 'N': - m->show_nr_of_instructions = 1; - msopts = 1; - break; - case 'n': - m->ncpus = atoi(optarg); - n_cpus_set = 1; - msopts = 1; - break; - case 'O': - m->force_netboot = 1; - msopts = 1; - break; - case 'o': - CHECK_ALLOCATION(m->boot_string_argument = - strdup(optarg)); - msopts = 1; - break; - case 'p': - machine_add_breakpoint_string(m, optarg); - msopts = 1; - break; - case 'Q': - m->prom_emulation = 0; - msopts = 1; - break; - case 'q': - quiet_mode = 1; - break; - case 'R': - m->use_random_bootstrap_cpu = 1; - msopts = 1; - break; - case 'r': - m->register_dump = 1; - msopts = 1; - break; - case 'S': - m->random_mem_contents = 1; - msopts = 1; - break; - case 's': - machine_statistics_init(m, optarg); - msopts = 1; - break; - case 'T': - m->halt_on_nonexistant_memaccess = 1; - msopts = 1; - break; - case 't': - m->show_trace_tree = 1; - msopts = 1; - break; - case 'U': - m->slow_serial_interrupts_hack_for_linux = 1; - msopts = 1; - break; - case 'V': - single_step = ENTER_SINGLE_STEPPING; - break; - case 'v': - verbose ++; - break; - case 'W': - internal_w(optarg); - exit(0); - case 'X': - m->x11_md.in_use = 1; - msopts = 1; - /* FALL-THROUGH */ - case 'x': - console_allow_slaves(1); - break; - case 'Y': - m->x11_md.scaledown = atoi(optarg); - if (m->x11_md.scaledown < -1) { - m->x11_md.scaleup = - m->x11_md.scaledown; - m->x11_md.scaledown = 1; - } - if (m->x11_md.scaledown < 1) { - fprintf(stderr, "Invalid scaledown value.\n"); - exit(1); - } - msopts = 1; - break; - case 'Z': - m->n_gfx_cards = atoi(optarg); - using_switch_Z = 1; - msopts = 1; - break; - case 'z': - m->x11_md.n_display_names ++; - CHECK_ALLOCATION(m->x11_md.display_names = (char **) realloc( - m->x11_md.display_names, - m->x11_md.n_display_names * sizeof(char *))); - CHECK_ALLOCATION(m->x11_md.display_names[ - m->x11_md.n_display_names-1] = strdup(optarg)); - msopts = 1; - break; - default: - fprintf(stderr, "Run %s -h for help on command " - "line options.\n", progname); - exit(1); - } - } - - argc -= optind; - argv += optind; - - extra_argc = argc; - extra_argv = argv; - - // If -V is used, -q is ignored. - if (single_step == ENTER_SINGLE_STEPPING) - quiet_mode = 0; - - if (type == NULL && subtype == NULL && - (single_step == ENTER_SINGLE_STEPPING || (argc > 0 && argv[0][0] != '@'))) { - int res2 = 0; - { - GXemul gxemul; - gxemul.InitUI(); - - if (single_step == ENTER_SINGLE_STEPPING) - gxemul.SetRunState(GXemul::Paused); - else - gxemul.SetRunState(GXemul::Running); - - gxemul.SetSnapshottingEnabled(using_switch_B); - - if (quiet_mode) - gxemul.SetQuietMode(true); - - if (argc > 0 && !gxemul.ParseFilenames("", argc, argv)) - res = 1; - - if (res2 == 0) - res2 = gxemul.Run(); - } - - // Note: exit() is outside the GXemul scope, so that GXemul's - // destructor runs. - exit(res2); - } - - if (type != NULL || subtype != NULL) { - if (type == NULL) - type = strdup(""); - if (subtype == NULL) - subtype = strdup(""); - - /* Is it a new machine mode? */ - if (subtype[0] != '\0') { - int res2 = 0; - bool doExit = false; - - { - GXemul gxemul; - gxemul.InitUI(); - - if (single_step == ENTER_SINGLE_STEPPING) - gxemul.SetRunState(GXemul::Paused); - else - gxemul.SetRunState(GXemul::Running); - - gxemul.SetSnapshottingEnabled(using_switch_B); - - if (quiet_mode) - gxemul.SetQuietMode(true); - - if (gxemul.IsTemplateMachine(subtype)) { - if (!gxemul.ParseFilenames(subtype, argc, argv)) - res2 = 1; - - if (res2 == 0) - res2 = gxemul.Run(); - - doExit = true; - } - } - - if (doExit) - exit(res2); - } - - /* Legacy mode? */ - res = machine_name_to_type(type, subtype, - &m->machine_type, &m->machine_subtype, &m->arch); - if (!res) - exit(1); - } - - if (m->machine_type == MACHINE_NONE && msopts) { - fprintf(stderr, "Machine specific options used directly on " - "the command line, but no machine\nemulation specified?\n"); - exit(1); - } - - - /* -i and -r are pretty verbose: */ - - if (m->instruction_trace && !verbose) { - fprintf(stderr, "Implicitly %sturning on -v, because" - " of -i\n", quiet_mode? "turning off -q and " : ""); - verbose = 1; - quiet_mode = 0; - } - - if (m->register_dump && !verbose) { - fprintf(stderr, "Implicitly %sturning on -v, because" - " of -r\n", quiet_mode? "turning off -q and " : ""); - verbose = 1; - quiet_mode = 0; - } - - - /* - * Usually, an executable filename must be supplied. - * - * However, it is possible to boot directly from a harddisk image - * file. If no kernel is supplied, but a diskimage is being used, - * then try to boot from disk. - */ - if (extra_argc == 0) { - if (using_switch_d) { - /* Booting directly from a disk image... */ - } else { - usage(0); - fprintf(stderr, "\nNo filename given. Aborting.\n"); - exit(1); - } - } else if (m->boot_kernel_filename[0] == '\0') { - /* - * Default boot_kernel_filename is "", which can be overriden - * by the -j command line option. If it is still "" here, - * and we're not booting directly from a disk image, then - * try to set it to the last part of the last file name - * given on the command line. (Last part = the stuff after - * the last slash.) - */ - char *s = extra_argv[extra_argc - 1]; - char *s2; - - s2 = strrchr(s, '/'); - if (s2 == NULL) - s2 = s; - else - s2 ++; - - CHECK_ALLOCATION(m->boot_kernel_filename = strdup(s2)); - } - - if (m->n_gfx_cards < 0 || m->n_gfx_cards > 3) { - fprintf(stderr, "Bad number of gfx cards (-Z).\n"); - exit(1); - } - - if (!using_switch_Z && !m->x11_md.in_use) - m->n_gfx_cards = 0; - - return 0; -} - - -/* - * main(): - * - * Two kinds of emulations are started from here: - * - * o) Simple emulations, using command line arguments, compatible with - * earlier version of GXemul/mips64emul. - * - * o) Emulations set up by parsing special config files. (0 or more.) - */ -int main(int argc, char *argv[]) -{ - /* Setting constants: */ - int constant_yes = 1; - int constant_true = 1; - int constant_no = 0; - int constant_false = 0; - - struct emul *emul; - int config_file = 0; - - char **diskimages = NULL; - int n_diskimages = 0; - int i; - - - progname = argv[0]; - - - /* - * Create the settings object, and add global settings to it: - * - * Read-only "constants": yes, no, true, false. - * Global emulator settings: verbose, single_step, ... - */ - global_settings = settings_new(); - - settings_add(global_settings, "yes", 0, SETTINGS_TYPE_INT, - SETTINGS_FORMAT_YESNO, (void *)&constant_yes); - settings_add(global_settings, "no", 0, SETTINGS_TYPE_INT, - SETTINGS_FORMAT_YESNO, (void *)&constant_no); - settings_add(global_settings, "true", 0, SETTINGS_TYPE_INT, - SETTINGS_FORMAT_BOOL, (void *)&constant_true); - settings_add(global_settings, "false", 0, SETTINGS_TYPE_INT, - SETTINGS_FORMAT_BOOL, (void *)&constant_false); - - /* Read-only settings: */ - settings_add(global_settings, "single_step", 0, - SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&single_step); - - /* Read/write settings: */ - settings_add(global_settings, "force_debugger_at_exit", 1, - SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, - (void *)&force_debugger_at_exit); - settings_add(global_settings, "verbose", 1, - SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&verbose); - settings_add(global_settings, "quiet_mode", 1, - SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&quiet_mode); - - /* Initialize all emulator subsystems: */ - console_init(); - cpu_init(); - device_init(); - machine_init(); - timer_init(); - - /* Create a simple emulation setup: */ - emul = emul_new(NULL); - settings_add(global_settings, "emul", 1, - SETTINGS_TYPE_SUBSETTINGS, 0, emul->settings); - - get_cmd_args(argc, argv, emul, &diskimages, &n_diskimages); - - if (!skip_srandom_call) { - struct timeval tv; - gettimeofday(&tv, NULL); - srandom(tv.tv_sec ^ getpid() ^ tv.tv_usec); - } - - /* Print startup message: */ - debug("GXemul " VERSION" " COPYRIGHT_MSG"\n" SECONDARY_MSG - "Read the source code and/or documentation for other Copyright " - "messages.\n\n"); - - /* Simple initialization, from command line arguments: */ - if (emul->machines[0]->machine_type != MACHINE_NONE) { - for (i=0; imachines[0], diskimages[i]); - - /* Make sure that there are no configuration files as well: */ - for (i=1; isettings); - - config_file = 1; - } - } - - if (emul->n_machines == 0) { - fprintf(stderr, "No emulations defined. Maybe you forgot to " - "use -E xx and/or -e yy, to specify\nthe machine type." - " For example:\n\n %s -e 3max -d disk.img\n\n" - "to boot an emulated DECstation 5000/200 with a disk " - "image.\n", progname); - exit(1); - } - - if (emul->machines[0]->machine_type == MACHINE_NONE) { - printf("No machine type specified? Run gxemul -H for a list\n" - "of available machine types. Use the -e or -E option(s)\n" - "to specify the machine type.\n"); - exit(1); - } - - device_set_exit_on_error(0); - console_warn_if_slaves_are_needed(1); - - - /* Run the emulation: */ - emul_run(emul); - - - /* - * Deinitialize everything: - */ - - console_deinit(); - - emul_destroy(emul); - - settings_remove_all(global_settings); - settings_destroy(global_settings); - - return 0; -} - diff -Nru gxemul-0.6.2/src/old_main/Makefile.skel gxemul-0.7.0+dfsg/src/old_main/Makefile.skel --- gxemul-0.6.2/src/old_main/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/Makefile.skel 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -# -# Makefile for GXemul src/old_main (from GXemul 0.4.x) -# - -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE) - -OBJS=emul.o emul_parse.o float_emul.o interrupt.o main.o memory.o misc.o \ - settings.o timer.o - -all: $(OBJS) - -$(OBJS): Makefile - -clean: - rm -f $(OBJS) *core - -clean_all: clean - rm -f Makefile - - diff -Nru gxemul-0.6.2/src/old_main/memory.cc gxemul-0.7.0+dfsg/src/old_main/memory.cc --- gxemul-0.6.2/src/old_main/memory.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/memory.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,1001 +0,0 @@ -/* - * Copyright (C) 2003-2009 Anders Gavare. 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. The name of the author 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. - * - * - * Functions for handling the memory of an emulated machine. - */ - -#include -#include -#include -#include -#include - -#include "cpu.h" -#include "machine.h" -#include "memory.h" -#include "misc.h" - - -extern int verbose; -extern int quiet_mode; - - -/* - * memory_readmax64(): - * - * Read at most 64 bits of data from a buffer. Length is given by - * len, and the byte order by cpu->byte_order. - * - * This function should not be called with cpu == NULL. - */ -uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len) -{ - int i, byte_order = cpu->byte_order; - uint64_t x = 0; - - if (len & MEM_PCI_LITTLE_ENDIAN) { - len &= ~MEM_PCI_LITTLE_ENDIAN; - byte_order = EMUL_LITTLE_ENDIAN; - } - - /* Switch byte order for incoming data, if necessary: */ - if (byte_order == EMUL_BIG_ENDIAN) - for (i=0; i=0; i--) { - x <<= 8; - x |= buf[i]; - } - - return x; -} - - -/* - * memory_writemax64(): - * - * Write at most 64 bits of data to a buffer. Length is given by - * len, and the byte order by cpu->byte_order. - * - * This function should not be called with cpu == NULL. - */ -void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, - uint64_t data) -{ - int i, byte_order = cpu->byte_order; - - if (len & MEM_PCI_LITTLE_ENDIAN) { - len &= ~MEM_PCI_LITTLE_ENDIAN; - byte_order = EMUL_LITTLE_ENDIAN; - } - - if (byte_order == EMUL_LITTLE_ENDIAN) - for (i=0; i>= 8; - } - else - for (i=0; i>= 8; - } -} - - -/* - * zeroed_alloc(): - * - * Allocates a block of memory using mmap(), and if that fails, try - * malloc() + memset(). The returned memory block contains only zeroes. - */ -void *zeroed_alloc(size_t s) -{ - void *p = mmap(NULL, s, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - - if (p == NULL) { -#if 1 - fprintf(stderr, "zeroed_alloc(): mmap() failed. This should" - " not usually happen. If you can reproduce this, then" - " please contact me with details about your run-time" - " environment.\n"); - exit(1); -#else - CHECK_ALLOCATION(p = malloc(s)); - memset(p, 0, s); -#endif - } - - return p; -} - - -/* - * memory_new(): - * - * This function creates a new memory object. An emulated machine needs one - * of these. - */ -struct memory *memory_new(uint64_t physical_max, int arch) -{ - struct memory *mem; - int bits_per_pagetable = BITS_PER_PAGETABLE; - int bits_per_memblock = BITS_PER_MEMBLOCK; - int entries_per_pagetable = 1 << BITS_PER_PAGETABLE; - int max_bits = MAX_BITS; - size_t s; - - CHECK_ALLOCATION(mem = (struct memory *) malloc(sizeof(struct memory))); - memset(mem, 0, sizeof(struct memory)); - - /* Check bits_per_pagetable and bits_per_memblock for sanity: */ - if (bits_per_pagetable + bits_per_memblock != max_bits) { - fprintf(stderr, "memory_new(): bits_per_pagetable and " - "bits_per_memblock mismatch\n"); - exit(1); - } - - mem->physical_max = physical_max; - mem->dev_dyntrans_alignment = 4095; - - s = entries_per_pagetable * sizeof(void *); - - mem->pagetable = (unsigned char *) mmap(NULL, s, - PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (mem->pagetable == NULL) { - CHECK_ALLOCATION(mem->pagetable = malloc(s)); - memset(mem->pagetable, 0, s); - } - - mem->mmap_dev_minaddr = 0xffffffffffffffffULL; - mem->mmap_dev_maxaddr = 0; - - return mem; -} - - -/* - * memory_points_to_string(): - * - * Returns 1 if there's something string-like in emulated memory at address - * addr, otherwise 0. - */ -int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, - int min_string_length) -{ - int cur_length = 0; - unsigned char c; - - for (;;) { - c = '\0'; - cpu->memory_rw(cpu, mem, addr+cur_length, - &c, sizeof(c), MEM_READ, CACHE_NONE | NO_EXCEPTIONS); - if (c=='\n' || c=='\t' || c=='\r' || (c>=' ' && c<127)) { - cur_length ++; - if (cur_length >= min_string_length) - return 1; - } else { - if (cur_length >= min_string_length) - return 1; - else - return 0; - } - } -} - - -/* - * memory_conv_to_string(): - * - * Convert emulated memory contents to a string, placing it in a buffer - * provided by the caller. - */ -char *memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr, - char *buf, int bufsize) -{ - int len = 0; - int output_index = 0; - unsigned char c, p='\0'; - - while (output_index < bufsize-1) { - c = '\0'; - cpu->memory_rw(cpu, mem, addr+len, &c, sizeof(c), MEM_READ, - CACHE_NONE | NO_EXCEPTIONS); - buf[output_index] = c; - if (c>=' ' && c<127) { - len ++; - output_index ++; - } else if (c=='\n' || c=='\r' || c=='\t') { - len ++; - buf[output_index] = '\\'; - output_index ++; - switch (c) { - case '\n': p = 'n'; break; - case '\r': p = 'r'; break; - case '\t': p = 't'; break; - } - if (output_index < bufsize-1) { - buf[output_index] = p; - output_index ++; - } - } else { - buf[output_index] = '\0'; - return buf; - } - } - - buf[bufsize-1] = '\0'; - return buf; -} - - -/* - * memory_device_dyntrans_access(): - * - * Get the lowest and highest dyntrans access since last time. - */ -void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem, - void *extra, uint64_t *low, uint64_t *high) -{ - size_t s; - int i, need_inval = 0; - - /* TODO: This is O(n), so it might be good to rewrite it some day. - For now, it will be enough, as long as this function is not - called too often. */ - - for (i=0; in_mmapped_devices; i++) { - if (mem->devices[i].extra == extra && - mem->devices[i].flags & DM_DYNTRANS_WRITE_OK && - mem->devices[i].dyntrans_data != NULL) { - if (mem->devices[i].dyntrans_write_low != (uint64_t) -1) - need_inval = 1; - if (low != NULL) - *low = mem->devices[i].dyntrans_write_low; - mem->devices[i].dyntrans_write_low = (uint64_t) -1; - - if (high != NULL) - *high = mem->devices[i].dyntrans_write_high; - mem->devices[i].dyntrans_write_high = 0; - - if (!need_inval) - return; - - /* Invalidate any pages of this device that might - be in the dyntrans load/store cache, by marking - the pages read-only. */ - if (cpu->invalidate_translation_caches != NULL) { - for (s = *low; s <= *high; - s += cpu->machine->arch_pagesize) - cpu->invalidate_translation_caches - (cpu, mem->devices[i].baseaddr + s, - JUST_MARK_AS_NON_WRITABLE - | INVALIDATE_PADDR); - } - - return; - } - } -} - - -/* - * memory_device_update_data(): - * - * Update a device' dyntrans data pointer. - * - * SUPER-IMPORTANT NOTE: Anyone who changes a dyntrans data pointer while - * things are running also needs to invalidate all CPUs' address translation - * caches! Otherwise, these may contain old pointers to the old data. - */ -void memory_device_update_data(struct memory *mem, void *extra, - unsigned char *data) -{ - int i; - - for (i=0; in_mmapped_devices; i++) { - if (mem->devices[i].extra != extra) - continue; - - mem->devices[i].dyntrans_data = data; - mem->devices[i].dyntrans_write_low = (uint64_t)-1; - mem->devices[i].dyntrans_write_high = 0; - } -} - - -/* - * memory_device_register(): - * - * Register a memory mapped device. - */ -void memory_device_register(struct memory *mem, const char *device_name, - uint64_t baseaddr, uint64_t len, - int (*f)(struct cpu *,struct memory *,uint64_t,unsigned char *, - size_t,int,void *), - void *extra, int flags, unsigned char *dyntrans_data) -{ - int i, newi = 0; - - /* - * Figure out at which index to insert this device, and simultaneously - * check for collisions: - */ - newi = -1; - for (i=0; in_mmapped_devices; i++) { - if (i == 0 && baseaddr + len <= mem->devices[i].baseaddr) - newi = i; - if (i > 0 && baseaddr + len <= mem->devices[i].baseaddr && - baseaddr >= mem->devices[i-1].endaddr) - newi = i; - if (i == mem->n_mmapped_devices - 1 && - baseaddr >= mem->devices[i].endaddr) - newi = i + 1; - - /* If this is not colliding with device i, then continue: */ - if (baseaddr + len <= mem->devices[i].baseaddr) - continue; - if (baseaddr >= mem->devices[i].endaddr) - continue; - - fatal("\nERROR! \"%s\" collides with device %i (\"%s\")!\n", - device_name, i, mem->devices[i].name); - exit(1); - } - if (mem->n_mmapped_devices == 0) - newi = 0; - if (newi == -1) { - fatal("INTERNAL ERROR\n"); - exit(1); - } - - if (verbose >= 2) { - /* (40 bits of physical address is displayed) */ - debug("device at 0x%010" PRIx64": %s", (uint64_t) baseaddr, - device_name); - - if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) - && (baseaddr & mem->dev_dyntrans_alignment) != 0) { - fatal("\nWARNING: Device dyntrans access, but unaligned" - " baseaddr 0x%" PRIx64".\n", (uint64_t) baseaddr); - } - - if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) { - debug(" (dyntrans %s)", - (flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R"); - } - debug("\n"); - } - - for (i=0; in_mmapped_devices; i++) { - if (dyntrans_data == mem->devices[i].dyntrans_data && - mem->devices[i].flags&(DM_DYNTRANS_OK|DM_DYNTRANS_WRITE_OK) - && flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) { - fatal("ERROR: the data pointer used for dyntrans " - "accesses must only be used once!\n"); - fatal("(%p cannot be used by '%s'; already in use by '" - "%s')\n", dyntrans_data, device_name, - mem->devices[i].name); - exit(1); - } - } - - mem->n_mmapped_devices++; - - CHECK_ALLOCATION(mem->devices = (struct memory_device *) realloc(mem->devices, - sizeof(struct memory_device) * mem->n_mmapped_devices)); - - /* Make space for the new entry: */ - if (newi + 1 != mem->n_mmapped_devices) - memmove(&mem->devices[newi+1], &mem->devices[newi], - sizeof(struct memory_device) - * (mem->n_mmapped_devices - newi - 1)); - - CHECK_ALLOCATION(mem->devices[newi].name = strdup(device_name)); - mem->devices[newi].baseaddr = baseaddr; - mem->devices[newi].endaddr = baseaddr + len; - mem->devices[newi].length = len; - mem->devices[newi].flags = flags; - mem->devices[newi].dyntrans_data = dyntrans_data; - - if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK) - && !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) { - fatal("\nERROR: Device dyntrans access, but dyntrans_data" - " = NULL!\n"); - exit(1); - } - - if ((size_t)dyntrans_data & (sizeof(void *) - 1)) { - fprintf(stderr, "memory_device_register():" - " dyntrans_data not aligned correctly (%p)\n", - dyntrans_data); - abort(); - } - - mem->devices[newi].dyntrans_write_low = (uint64_t)-1; - mem->devices[newi].dyntrans_write_high = 0; - mem->devices[newi].f = f; - mem->devices[newi].extra = extra; - - if (baseaddr < mem->mmap_dev_minaddr) - mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment; - if (baseaddr + len > mem->mmap_dev_maxaddr) - mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) | - mem->dev_dyntrans_alignment) + 1; - - if (newi < mem->last_accessed_device) - mem->last_accessed_device ++; -} - - -/* - * memory_device_remove(): - * - * Unregister a memory mapped device from a memory object. - */ -void memory_device_remove(struct memory *mem, int i) -{ - if (i < 0 || i >= mem->n_mmapped_devices) { - fatal("memory_device_remove(): invalid device number %i\n", i); - exit(1); - } - - mem->n_mmapped_devices --; - - if (i == mem->n_mmapped_devices) - return; - - memmove(&mem->devices[i], &mem->devices[i+1], - sizeof(struct memory_device) * (mem->n_mmapped_devices - i)); - - if (i <= mem->last_accessed_device) - mem->last_accessed_device --; - if (mem->last_accessed_device < 0) - mem->last_accessed_device = 0; -} - - -/* - * memory_paddr_to_hostaddr(): - * - * Translate a physical address into a host address. The usual way to call - * this function is to make sure that paddr is page aligned, which will result - * in the host _page_ corresponding to that address. - * - * Return value is a pointer to the address in the host, or NULL on failure. - * On reads, a NULL return value should be interpreted as reading all zeroes. - */ -unsigned char *memory_paddr_to_hostaddr(struct memory *mem, - uint64_t paddr, int writeflag) -{ - void **table; - int entry; - const int mask = (1 << BITS_PER_PAGETABLE) - 1; - const int shrcount = MAX_BITS - BITS_PER_PAGETABLE; - unsigned char *hostptr; - - table = (void **) mem->pagetable; - entry = (paddr >> shrcount) & mask; - - /* printf("memory_paddr_to_hostaddr(): p=%16" PRIx64 - " w=%i => entry=0x%x\n", (uint64_t) paddr, writeflag, entry); */ - - if (table[entry] == NULL) { - size_t alloclen; - - /* - * Special case: reading from a nonexistant memblock - * returns all zeroes, and doesn't allocate anything. - * (If any intermediate pagetable is nonexistant, then - * the same thing happens): - */ - if (writeflag == MEM_READ) - return NULL; - - /* Allocate a memblock: */ - alloclen = 1 << BITS_PER_MEMBLOCK; - - /* printf(" allocating for entry %i, len=%i\n", - entry, alloclen); */ - - /* Anonymous mmap() should return zero-filled memory, - try malloc + memset if mmap failed. */ - table[entry] = (void *) mmap(NULL, alloclen, - PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (table[entry] == NULL) { - CHECK_ALLOCATION(table[entry] = malloc(alloclen)); - memset(table[entry], 0, alloclen); - } - } - - hostptr = (unsigned char *) table[entry]; - - if (hostptr != NULL) - hostptr += (paddr & ((1 << BITS_PER_MEMBLOCK) - 1)); - - return hostptr; -} - - -#define UPDATE_CHECKSUM(value) { \ - internal_state -= 0x118c7771c0c0a77fULL; \ - internal_state = ((internal_state + (value)) << 7) ^ \ - (checksum >> 11) ^ ((checksum - (value)) << 3) ^ \ - (internal_state - checksum) ^ ((value) - internal_state); \ - checksum ^= internal_state; \ - } - - -/* - * memory_checksum(): - * - * Calculate a 64-bit checksum of everything in a struct memory. This is - * useful for tracking down bugs; an old (presumably working) version of - * the emulator can be compared to a newer (buggy) version. - */ -uint64_t memory_checksum(struct memory *mem) -{ - uint64_t internal_state = 0x80624185376feff2ULL; - uint64_t checksum = 0xcb9a87d5c010072cULL; - const size_t n_entries = (1 << BITS_PER_PAGETABLE) - 1; - const size_t len = (1 << BITS_PER_MEMBLOCK) / sizeof(uint64_t); - size_t entry, i; - - for (entry=0; entry<=n_entries; entry++) { - uint64_t **table = (uint64_t **) mem->pagetable; - uint64_t *memblock = table[entry]; - - if (memblock == NULL) { - UPDATE_CHECKSUM(0x1198ab7c8174a76fULL); - continue; - } - - for (i=0; ipc; - char *symbol; - - /* - * This allows guest OS kernels to probe memory a few KBs past the - * end of memory, without giving too many warnings. - */ - if (paddr < mem->physical_max + 0x40000) - return; - - if (!cpu->machine->halt_on_nonexistant_memaccess && quiet_mode) - return; - - fatal("[ memory_rw(): %s ", writeflag? "write":"read"); - - if (writeflag) { - unsigned int i; - debug("data={", writeflag); - if (len > 16) { - int start2 = len-16; - for (i=0; i<16; i++) - debug("%s%02x", i?",":"", data[i]); - debug(" .. "); - if (start2 < 16) - start2 = 16; - for (i=start2; i= physical_max; pc=", paddr); - if (cpu->is_32bit) - fatal("0x%08" PRIx32, (uint32_t) old_pc); - else - fatal("0x%016" PRIx64, (uint64_t) old_pc); - symbol = get_symbol_name(&cpu->machine->symbol_context, - old_pc, &offset); - fatal(" <%s> ]\n", symbol? symbol : " no symbol "); - - if (cpu->machine->halt_on_nonexistant_memaccess) { - /* TODO: Halt in a nicer way. Not possible with the - current dyntrans system... */ - exit(1); - } -} - - -/* - * dump_mem_string(): - * - * Dump the contents of emulated RAM as readable text. Bytes that aren't - * readable are dumped in [xx] notation, where xx is in hexadecimal. - * Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating - * zero byte is found. - */ -#define DUMP_MEM_STRING_MAX 45 -void dump_mem_string(struct cpu *cpu, uint64_t addr) -{ - int i; - for (i=0; imemory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch), - MEM_READ, CACHE_DATA | NO_EXCEPTIONS); - if (ch == '\0') - return; - if (ch >= ' ' && ch < 126) - debug("%c", ch); - else - debug("[%02x]", ch); - } -} - - -/* - * store_byte(): - * - * Stores a byte in emulated ram. (Helper function.) - */ -void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data) -{ - if ((addr >> 32) == 0) - addr = (int64_t)(int32_t)addr; - cpu->memory_rw(cpu, cpu->mem, - addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA); -} - - -/* - * store_string(): - * - * Stores chars into emulated RAM until a zero byte (string terminating - * character) is found. The zero byte is also copied. - * (strcpy()-like helper function, host-RAM-to-emulated-RAM.) - */ -void store_string(struct cpu *cpu, uint64_t addr, const char *s) -{ - do { - store_byte(cpu, addr++, *s); - } while (*s++); -} - - -/* - * add_environment_string(): - * - * Like store_string(), but advances the pointer afterwards. The most - * obvious use is to place a number of strings (such as environment variable - * strings) after one-another in emulated memory. - */ -void add_environment_string(struct cpu *cpu, const char *s, uint64_t *addr) -{ - store_string(cpu, *addr, s); - (*addr) += strlen(s) + 1; -} - - -/* - * add_environment_string_dual(): - * - * Add "dual" environment strings, one for the variable name and one for the - * value, and update pointers afterwards. - */ -void add_environment_string_dual(struct cpu *cpu, - uint64_t *ptrp, uint64_t *addrp, const char *s1, const char *s2) -{ - uint64_t ptr = *ptrp, addr = *addrp; - - store_32bit_word(cpu, ptr, addr); - ptr += sizeof(uint32_t); - if (addr != 0) { - store_string(cpu, addr, s1); - addr += strlen(s1) + 1; - } - store_32bit_word(cpu, ptr, addr); - ptr += sizeof(uint32_t); - if (addr != 0) { - store_string(cpu, addr, s2); - addr += strlen(s2) + 1; - } - - *ptrp = ptr; - *addrp = addr; -} - - -/* - * store_64bit_word(): - * - * Stores a 64-bit word in emulated RAM. Byte order is taken into account. - * Helper function. - */ -int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64) -{ - unsigned char data[8]; - if ((addr >> 32) == 0) - addr = (int64_t)(int32_t)addr; - data[0] = (data64 >> 56) & 255; - data[1] = (data64 >> 48) & 255; - data[2] = (data64 >> 40) & 255; - data[3] = (data64 >> 32) & 255; - data[4] = (data64 >> 24) & 255; - data[5] = (data64 >> 16) & 255; - data[6] = (data64 >> 8) & 255; - data[7] = (data64) & 255; - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[7]; data[7] = tmp; - tmp = data[1]; data[1] = data[6]; data[6] = tmp; - tmp = data[2]; data[2] = data[5]; data[5] = tmp; - tmp = data[3]; data[3] = data[4]; data[4] = tmp; - } - return cpu->memory_rw(cpu, cpu->mem, - addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); -} - - -/* - * store_32bit_word(): - * - * Stores a 32-bit word in emulated RAM. Byte order is taken into account. - * (This function takes a 64-bit word as argument, to suppress some - * warnings, but only the lowest 32 bits are used.) - */ -int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32) -{ - unsigned char data[4]; - - data[0] = (data32 >> 24) & 255; - data[1] = (data32 >> 16) & 255; - data[2] = (data32 >> 8) & 255; - data[3] = (data32) & 255; - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[3]; data[3] = tmp; - tmp = data[1]; data[1] = data[2]; data[2] = tmp; - } - return cpu->memory_rw(cpu, cpu->mem, - addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); -} - - -/* - * store_16bit_word(): - * - * Stores a 16-bit word in emulated RAM. Byte order is taken into account. - * (This function takes a 64-bit word as argument, to suppress some - * warnings, but only the lowest 16 bits are used.) - */ -int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16) -{ - unsigned char data[2]; - - data[0] = (data16 >> 8) & 255; - data[1] = (data16) & 255; - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[1]; data[1] = tmp; - } - return cpu->memory_rw(cpu, cpu->mem, - addr, data, sizeof(data), MEM_WRITE, CACHE_DATA); -} - - -/* - * store_buf(): - * - * memcpy()-like helper function, from host RAM to emulated RAM. - */ -void store_buf(struct cpu *cpu, uint64_t addr, const char *s, size_t len) -{ - size_t psize = 1024; /* 1024 256 64 16 4 1 */ - - while (len != 0) { - if ((addr & (psize-1)) == 0) { - while (len >= psize) { - cpu->memory_rw(cpu, cpu->mem, addr, - (unsigned char *)s, psize, MEM_WRITE, - CACHE_DATA); - addr += psize; - s += psize; - len -= psize; - } - } - psize >>= 2; - } - - while (len-- != 0) - store_byte(cpu, addr++, *s++); -} - - -/* - * store_pointer_and_advance(): - * - * Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the - * target address. (Useful for e.g. ARCBIOS environment initialization.) - */ -void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp, - uint64_t data, int flag64) -{ - uint64_t addr = *addrp; - if (flag64) { - store_64bit_word(cpu, addr, data); - addr += 8; - } else { - store_32bit_word(cpu, addr, data); - addr += 4; - } - *addrp = addr; -} - - -/* - * load_64bit_word(): - * - * Helper function. Emulated byte order is taken into account. - */ -uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr) -{ - unsigned char data[8]; - - cpu->memory_rw(cpu, cpu->mem, - addr, data, sizeof(data), MEM_READ, CACHE_DATA); - - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[7]; data[7] = tmp; - tmp = data[1]; data[1] = data[6]; data[6] = tmp; - tmp = data[2]; data[2] = data[5]; data[5] = tmp; - tmp = data[3]; data[3] = data[4]; data[4] = tmp; - } - - return - ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) + - ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) + - ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) + - ((uint64_t)data[6] << 8) + (uint64_t)data[7]; -} - - -/* - * load_32bit_word(): - * - * Helper function. Emulated byte order is taken into account. - */ -uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr) -{ - unsigned char data[4]; - - cpu->memory_rw(cpu, cpu->mem, - addr, data, sizeof(data), MEM_READ, CACHE_DATA); - - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[3]; data[3] = tmp; - tmp = data[1]; data[1] = data[2]; data[2] = tmp; - } - - return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]; -} - - -/* - * load_16bit_word(): - * - * Helper function. Emulated byte order is taken into account. - */ -uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr) -{ - unsigned char data[2]; - - cpu->memory_rw(cpu, cpu->mem, - addr, data, sizeof(data), MEM_READ, CACHE_DATA); - - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[1]; data[1] = tmp; - } - - return (data[0] << 8) + data[1]; -} - - -/* - * store_64bit_word_in_host(): - * - * Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken - * into account. This is useful when building structs in the host's RAM - * which will later be copied into emulated RAM. - */ -void store_64bit_word_in_host(struct cpu *cpu, - unsigned char *data, uint64_t data64) -{ - data[0] = (data64 >> 56) & 255; - data[1] = (data64 >> 48) & 255; - data[2] = (data64 >> 40) & 255; - data[3] = (data64 >> 32) & 255; - data[4] = (data64 >> 24) & 255; - data[5] = (data64 >> 16) & 255; - data[6] = (data64 >> 8) & 255; - data[7] = (data64) & 255; - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[7]; data[7] = tmp; - tmp = data[1]; data[1] = data[6]; data[6] = tmp; - tmp = data[2]; data[2] = data[5]; data[5] = tmp; - tmp = data[3]; data[3] = data[4]; data[4] = tmp; - } -} - - -/* - * store_32bit_word_in_host(): - * - * See comment for store_64bit_word_in_host(). - * - * (Note: The data32 parameter is a uint64_t. This is done to suppress - * some warnings.) - */ -void store_32bit_word_in_host(struct cpu *cpu, - unsigned char *data, uint64_t data32) -{ - data[0] = (data32 >> 24) & 255; - data[1] = (data32 >> 16) & 255; - data[2] = (data32 >> 8) & 255; - data[3] = (data32) & 255; - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[3]; data[3] = tmp; - tmp = data[1]; data[1] = data[2]; data[2] = tmp; - } -} - - -/* - * store_16bit_word_in_host(): - * - * See comment for store_64bit_word_in_host(). - */ -void store_16bit_word_in_host(struct cpu *cpu, - unsigned char *data, uint16_t data16) -{ - data[0] = (data16 >> 8) & 255; - data[1] = (data16) & 255; - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - int tmp = data[0]; data[0] = data[1]; data[1] = tmp; - } -} - diff -Nru gxemul-0.6.2/src/old_main/misc.cc gxemul-0.7.0+dfsg/src/old_main/misc.cc --- gxemul-0.6.2/src/old_main/misc.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/misc.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2005-2018 Anders Gavare. 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. The name of the author 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. - * - * - * This file contains things that don't fit anywhere else, and fake/dummy - * implementations of libc functions that are missing on some systems. - */ - -#include -#include -#include -#include - -#include "cpu.h" -#include "misc.h" - - -/* - * mystrtoull(): - * - * This function is used on OSes that don't have strtoull() in libc. - */ -unsigned long long mystrtoull(const char *s, char **endp, int base) -{ - unsigned long long res = 0; - int minus_sign = 0; - - if (s == NULL) - return 0; - - /* TODO: Implement endp? */ - if (endp != NULL) { - fprintf(stderr, "mystrtoull(): endp isn't implemented\n"); - exit(1); - } - - if (s[0] == '-') { - minus_sign = 1; - s++; - } - - /* Guess base: */ - if (base == 0) { - if (s[0] == '0') { - /* Just "0"? :-) */ - if (!s[1]) - return 0; - if (s[1] == 'x' || s[1] == 'X') { - base = 16; - s += 2; - } else { - base = 8; - s ++; - } - } else if (s[0] >= '1' && s[0] <= '9') - base = 10; - } - - while (s[0]) { - int c = s[0]; - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - c = c - 'A' + 10; - else - break; - switch (base) { - case 8: res = (res << 3) | c; - break; - case 16:res = (res << 4) | c; - break; - default:res = (res * base) + c; - } - s++; - } - - if (minus_sign) - res = (uint64_t) -(int64_t)res; - return res; -} - - -/* - * mymkstemp(): - * - * mkstemp() replacement for systems that lack that function. This is NOT - * really safe, but should at least allow the emulator to build and run. - */ -int mymkstemp(char *templ) -{ - int h = 0; - char *p = templ; - - while (*p) { - if (*p == 'X') - *p = 48 + random() % 10; - p++; - } - - h = open(templ, O_RDWR | O_CREAT | O_EXCL, 0600); - return h; -} - - -#ifdef USE_STRLCPY_REPLACEMENTS -/* - * mystrlcpy(): - * - * Quick hack strlcpy() replacement for systems that lack that function. - * NOTE: No length checking is done. - */ -size_t mystrlcpy(char *dst, const char *src, size_t size) -{ - strcpy(dst, src); - return strlen(src); -} - - -/* - * mystrlcat(): - * - * Quick hack strlcat() replacement for systems that lack that function. - * NOTE: No length checking is done. - */ -size_t mystrlcat(char *dst, const char *src, size_t size) -{ - size_t orig_dst_len = strlen(dst); - strcat(dst, src); - return strlen(src) + orig_dst_len; -} -#endif - - -/* - * print_separator_line(): - * - * Prints a line of "----------". - */ -void print_separator_line(void) -{ - int i = 79; - while (i-- > 0) - debug("-"); - debug("\n"); -} - diff -Nru gxemul-0.6.2/src/old_main/settings.cc gxemul-0.7.0+dfsg/src/old_main/settings.cc --- gxemul-0.6.2/src/old_main/settings.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/settings.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,506 +0,0 @@ -/* - * Copyright (C) 2006-2009 Anders Gavare. 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. The name of the author 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. - * - * - * A generic settings object. (This module should be 100% indepedent of GXemul - * and hence easily reusable.) It is basically a tree structure of nodes, - * where each node has a name and a few properties. The main property is - * a pointer, which can either point to other settings ("sub-settings"), - * or to a variable in memory. - * - * Appart from the pointer, the other properties are a definition of the - * type being pointed to (int, int32_t, int64_t, char*, etc), how it should be - * presented (e.g. it may be an int value in memory, but it should be - * presented as a boolean "true/false" value), and a flag which tells us - * whether the setting is directly writable or not. - * - * If UNSTABLE_DEVEL is defined, then warnings are printed when - * settings_destroy() is called if individual settings have not yet been - * deleted. (This is to help making sure that code which uses the settings - * subsystem correctly un-initializes stuff.) - */ - -#include -#include -#include - -/* Including misc.h should ONLY be necessary to work around the fact that - many systems don't have PRIx64 etc defined. */ -#include "misc.h" - -#include "settings.h" - - -struct settings { - struct settings *parent; - char *name_in_parent; - - int n_settings; - - /* - * Each setting has a name, a writable flag, a storage type, a - * presentation format, and a pointer. - * - * For subsettings, the pointer points to the subsettings object; - * for other settings, the pointer points to a variable. - * - * These pointers point to simple linear arrays, containing n_settings - * entries each. - */ - - char **name; - int *writable; - int *storage_type; - int *presentation_format; - void **ptr; -}; - - -/* - * settings_new(): - * - * Create a new settings object. Return value is a pointer to the newly - * created object. The function does not return on failure. - */ -struct settings *settings_new(void) -{ - struct settings *settings; - - CHECK_ALLOCATION(settings = (struct settings *) malloc(sizeof(struct settings))); - memset(settings, 0, sizeof(struct settings)); - - return settings; -} - - -/* - * settings_destroy(): - * - * Frees all resources occupied by a settings object. Also, if this settings - * object has a parent, then remove it from the parent. - */ -void settings_destroy(struct settings *settings) -{ - int i; - - if (settings == NULL) { - fprintf(stderr, "settings_destroy(): internal error, " - "settings = NULL!\n"); - exit(1); - } - -#ifdef UNSTABLE_DEVEL - if (settings->n_settings > 0) - printf("settings_destroy(): there are remaining settings!\n"); -#endif - - if (settings->name != NULL) { - for (i=0; in_settings; i++) { - if (settings->name[i] != NULL) { -#ifdef UNSTABLE_DEVEL - printf("settings_destroy(): setting '%s'" - " was not properly deleted before " - "exiting!\n", settings->name[i]); -#endif - free(settings->name[i]); - } - } - - free(settings->name); - } else if (settings->n_settings != 0) { - fprintf(stderr, "settings_destroy(): internal error, " - "settings->name = NULL, but there were settings?" - " (n_settings = %i)\n", settings->n_settings); - exit(1); - } - - if (settings->writable != NULL) - free(settings->writable); - - if (settings->storage_type != NULL) - free(settings->storage_type); - - if (settings->presentation_format != NULL) - free(settings->presentation_format); - - if (settings->ptr != NULL) - free(settings->ptr); - - if (settings->parent != NULL) { - settings_remove(settings->parent, settings->name_in_parent); - free(settings->name_in_parent); - } - - free(settings); -} - - -/* - * settings_read(): - * - * Used internally by settings_access() and settings_debugdump(). - */ -static int settings_read(struct settings *settings, int i, uint64_t *valuep) -{ - *valuep = 0; - - switch (settings->storage_type[i]) { - case SETTINGS_TYPE_INT: - *valuep = *((int *) settings->ptr[i]); - break; - case SETTINGS_TYPE_INT8: - *valuep = *((int8_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_INT16: - *valuep = *((int16_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_INT32: - *valuep = *((int32_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_INT64: - *valuep = *((int64_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_UINT: - *valuep = *((uint *) settings->ptr[i]); - break; - case SETTINGS_TYPE_UINT8: - *valuep = *((uint8_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_UINT16: - *valuep = *((uint16_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_UINT32: - *valuep = *((uint32_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_UINT64: - *valuep = *((uint64_t *) settings->ptr[i]); - break; - case SETTINGS_TYPE_STRING: - /* Note: Strings cannot be read like this. */ - break; - default:printf("settings_read(): FATAL ERROR! Unknown storage type" - ": %i\n", settings->storage_type[i]); - exit(1); - } - - return SETTINGS_OK; -} - - -/* - * settings_write(): - * - * Used internally by settings_access(). - */ -static int settings_write(struct settings *settings, int i, uint64_t *valuep) -{ - if (!settings->writable[i]) - return SETTINGS_READONLY; - - switch (settings->storage_type[i]) { - case SETTINGS_TYPE_INT: - case SETTINGS_TYPE_UINT: - *((int *) settings->ptr[i]) = *valuep; - break; - case SETTINGS_TYPE_INT8: - case SETTINGS_TYPE_UINT8: - *((int8_t *) settings->ptr[i]) = *valuep; - break; - case SETTINGS_TYPE_INT16: - case SETTINGS_TYPE_UINT16: - *((int16_t *) settings->ptr[i]) = *valuep; - break; - case SETTINGS_TYPE_INT32: - case SETTINGS_TYPE_UINT32: - *((int32_t *) settings->ptr[i]) = *valuep; - break; - case SETTINGS_TYPE_INT64: - case SETTINGS_TYPE_UINT64: - *((int64_t *) settings->ptr[i]) = *valuep; - break; - case SETTINGS_TYPE_STRING: - /* Note: Strings cannot be read like this. */ - printf("settings_write(): ERROR! Strings cannot be " - "written like this.\n"); - break; - default:printf("settings_read(): FATAL ERROR! Unknown storage type" - ": %i\n", settings->storage_type[i]); - exit(1); - } - - return SETTINGS_OK; -} - - -/* - * settings_debugdump(): - * - * Dump settings in a settings object to stdout. - * If recurse is non-zero, all subsetting objects are also dumped. - */ -void settings_debugdump(struct settings *settings, const char *prefix, - int recurse) -{ - size_t name_buflen = strlen(prefix) + 100; - char *name; - int i; - uint64_t value = 0; - - CHECK_ALLOCATION(name = (char *) malloc(name_buflen)); - - for (i=0; in_settings; i++) { - snprintf(name, name_buflen, "%s.%s", prefix, settings->name[i]); - - if (settings->storage_type[i] == SETTINGS_TYPE_SUBSETTINGS) { - /* Subsettings: */ - if (recurse) - settings_debugdump((struct settings *)settings->ptr[i], name, 1); - } else { - /* Normal value: */ - printf("%s = ", name); - - settings_read(settings, i, &value); - - switch (settings->presentation_format[i]) { - case SETTINGS_FORMAT_DECIMAL: - printf("%" PRIi64, value); - break; - case SETTINGS_FORMAT_HEX8: - printf("0x%02" PRIx8, (int8_t) value); - break; - case SETTINGS_FORMAT_HEX16: - printf("0x%04" PRIx16, (int16_t) value); - break; - case SETTINGS_FORMAT_HEX32: - printf("0x%08" PRIx32, (int32_t) value); - break; - case SETTINGS_FORMAT_HEX64: - printf("0x%016" PRIx64, (int64_t) value); - break; - case SETTINGS_FORMAT_BOOL: - printf(value? "true" : "false"); - break; - case SETTINGS_FORMAT_YESNO: - printf(value? "yes" : "no"); - break; - case SETTINGS_FORMAT_STRING: - printf("\"%s\"", *((char **)settings->ptr[i])); - break; - default:printf("FATAL ERROR! Unknown presentation " - "format: %i\n", - settings->presentation_format[i]); - exit(1); - } - - if (!settings->writable[i]) - printf(" (R/O)"); - - printf("\n"); - } - } - - free(name); -} - - -/* - * settings_add(): - * - * Add a setting to a settings object. - */ -void settings_add(struct settings *settings, const char *name, int writable, - int type, int format, void *ptr) -{ - int i; - - for (i=0; in_settings; i++) { - if (strcmp(settings->name[i], name) == 0) - break; - } - - if (i < settings->n_settings) { - fprintf(stderr, "settings_add(): name '%s' is already" - " in use\n", name); - exit(1); - } - - settings->n_settings ++; - - CHECK_ALLOCATION(settings->name = (char **) realloc(settings->name, - settings->n_settings * sizeof(char *))); - CHECK_ALLOCATION(settings->writable = (int *) realloc(settings->writable, - settings->n_settings * sizeof(int))); - CHECK_ALLOCATION(settings->storage_type = (int *) realloc( - settings->storage_type, settings->n_settings * sizeof(int))); - CHECK_ALLOCATION(settings->presentation_format = (int *) realloc(settings-> - presentation_format, settings->n_settings * sizeof(int))); - CHECK_ALLOCATION(settings->ptr = (void **) realloc(settings->ptr, - settings->n_settings * sizeof(void *))); - - CHECK_ALLOCATION(settings->name[settings->n_settings - 1] = - strdup(name)); - settings->writable[settings->n_settings - 1] = writable; - settings->storage_type[settings->n_settings - 1] = type; - settings->presentation_format[settings->n_settings - 1] = format; - settings->ptr[settings->n_settings - 1] = ptr; - - if (type == SETTINGS_TYPE_SUBSETTINGS) { - ((struct settings *)ptr)->parent = settings; - CHECK_ALLOCATION( ((struct settings *)ptr)->name_in_parent = - strdup(name) ); - } -} - - -/* - * settings_remove(): - * - * Remove a setting from a settings object. - */ -void settings_remove(struct settings *settings, const char *name) -{ - int i, m; - - for (i=0; in_settings; i++) { - if (strcmp(settings->name[i], name) == 0) - break; - } - - if (i >= settings->n_settings) { -#ifdef UNSTABLE_DEVEL - fprintf(stderr, "settings_remove(): attempting to remove" - " non-existant setting '%s'\n", name); -#endif - return; - } - - /* Check subsettings specifically: */ - if (settings->storage_type[i] == SETTINGS_TYPE_SUBSETTINGS && - settings->ptr[i] != NULL) { - struct settings *subsettings = (struct settings *) settings->ptr[i]; - if (subsettings->n_settings != 0) { - fprintf(stderr, "settings_remove(): attempting to " - "remove non-emtpy setting '%s'\n", name); - fprintf(stderr, "Remaining settings are:\n"); - for (i=0; in_settings; i++) - fprintf(stderr, "\t%s\n", subsettings->name[i]); - exit(1); - } - } - - settings->n_settings --; - free(settings->name[i]); - - m = settings->n_settings - i; - if (m == 0) - return; - - memmove(&settings->name[i], &settings->name[i+1], - m * sizeof(settings->name[0])); - memmove(&settings->writable[i], &settings->writable[i+1], - m * sizeof(settings->writable[0])); - memmove(&settings->storage_type[i], &settings->storage_type[i+1], - m * sizeof(settings->storage_type[0])); - memmove(&settings->presentation_format[i], - &settings->presentation_format[i+1], - m * sizeof(settings->presentation_format[0])); - memmove(&settings->ptr[i], &settings->ptr[i+1], - m * sizeof(settings->ptr[0])); -} - - -/* - * settings_remove_all(): - * - * Remove all (level-1) settings from a settings object. By level-1, I mean - * all settings that do not contain subsettings. - */ -void settings_remove_all(struct settings *settings) -{ - while (settings->n_settings > 0) - settings_remove(settings, settings->name[0]); -} - - -/* - * settings_access(): - * - * Read or write a setting. fullname may be something like "settings.x.y". - * When writing a value, valuebuf should point to a uint64_t containing the - * new value (note: always a uint64_t). When reading a value, valuebuf should - * point to a uint64_t where the value will be stored. - * - * The return value is one of the following: - * - * SETTINGS_OK - * The value was read or written. - * - * SETTINGS_NAME_NOT_FOUND - * The name was not found in the settings object. - * - * SETTINGS_READONLY - * The name was found, but it was marked as read-only, and - * an attempt was made to write to it. - */ -int settings_access(struct settings *settings, const char *fullname, - int writeflag, uint64_t *valuep) -{ - int i; - - /* printf("settings_access(fullname='%s')\n", fullname); */ - - if (strncmp(fullname, GLOBAL_SETTINGS_NAME".", - strlen(GLOBAL_SETTINGS_NAME) + 1) == 0) - fullname += strlen(GLOBAL_SETTINGS_NAME) + 1; - - for (i=0; in_settings; i++) { - size_t settings_name_len = strlen(settings->name[i]); - - if (strncmp(fullname, settings->name[i], - settings_name_len) != 0) - continue; - - /* Found the correct setting? */ - if (fullname[settings_name_len] == '\0') { - if (writeflag) - return settings_write(settings, i, valuep); - else - return settings_read(settings, i, valuep); - } - - /* Found a setting which has sub-settings? */ - if (fullname[settings_name_len] == '.') { - /* Recursive search: */ - return settings_access( - (struct settings *)settings->ptr[i], - fullname + settings_name_len + 1, - writeflag, valuep); - } - } - - return SETTINGS_NAME_NOT_FOUND; -} - diff -Nru gxemul-0.6.2/src/old_main/timer.cc gxemul-0.7.0+dfsg/src/old_main/timer.cc --- gxemul-0.6.2/src/old_main/timer.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/old_main/timer.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2006-2019 Anders Gavare. 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. The name of the author 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. - * - * - * Timer framework. This is used by emulated clocks. - */ - -#include -#include -#include -#include -#include -#include - -#include "misc.h" -#include "timer.h" - - -/* #define TEST */ - - -struct timer { - struct timer *next; - - double freq; - void (*timer_tick)(struct timer *timer, void *extra); - void *extra; - - double interval; - double next_tick_at; -}; - -static struct timer *first_timer = NULL; -struct timeval timer_start_tv; -static double timer_freq; -static int timer_countdown_to_next_gettimeofday; -static double timer_current_time; -static double timer_current_time_step; - -static int timer_is_running; - -#define SECONDS_BETWEEN_GETTIMEOFDAY_SYNCH 1.65 - - -/* - * timer_add(): - * - * Adds a virtual timer to the list of timers. - * - * Return value is a pointer to a timer struct. - */ -struct timer *timer_add(double freq, void (*timer_tick)(struct timer *timer, - void *extra), void *extra) -{ - struct timer *newtimer; - - CHECK_ALLOCATION(newtimer = (struct timer *) malloc(sizeof(struct timer))); - - if (freq <= 0.00000001) - freq = 0.00000001; - - newtimer->freq = freq; - newtimer->timer_tick = timer_tick; - newtimer->extra = extra; - - newtimer->interval = 1.0 / freq; - newtimer->next_tick_at = timer_current_time + newtimer->interval; - - newtimer->next = first_timer; - first_timer = newtimer; - - return newtimer; -} - - -/* - * timer_remove(): - * - * Removes a virtual timer from the list of timers. - */ -void timer_remove(struct timer *t) -{ - struct timer *prev = NULL, *cur = first_timer; - - while (cur != NULL && cur != t) { - prev = cur; - cur = cur->next; - } - - if (cur == t) { - if (prev == NULL) - first_timer = cur->next; - else - prev->next = cur->next; - free(cur); - } else { - fprintf(stderr, "attempt to remove timer %p which " - "doesn't exist. aborting\n", t); - exit(1); - } -} - - -/* - * timer_update_frequency(): - * - * Changes the frequency of an existing timer. - */ -void timer_update_frequency(struct timer *t, double new_freq) -{ - if (t->freq == new_freq) - return; - - t->freq = new_freq; - - if (new_freq <= 0.00000001) - new_freq = 0.00000001; - - t->interval = 1.0 / new_freq; - t->next_tick_at = timer_current_time + t->interval; -} - - -/* - * timer_tick(): - * - * Timer tick handler. This is where the interesting stuff happens. - */ -static void timer_tick(int signal_nr) -{ - struct timer *timer = first_timer; - struct timeval tv; - - timer_current_time += timer_current_time_step; - - if ((--timer_countdown_to_next_gettimeofday) < 0) { - gettimeofday(&tv, NULL); - tv.tv_sec -= timer_start_tv.tv_sec; - tv.tv_usec -= timer_start_tv.tv_usec; - if (tv.tv_usec < 0) { - tv.tv_usec += 1000000; - tv.tv_sec --; - } - -#ifdef TIMER_DEBUG - /* For debugging/testing: */ - { - double diff = tv.tv_usec * 0.000001 + tv.tv_sec - - timer_current_time; - printf("timer: lagging behind %f seconds\n", diff); - } -#endif - - /* Get exponentially closer to the real time, instead of - just changing to it directly: */ - timer_current_time = ( (tv.tv_usec * 0.000001 + tv.tv_sec) + - timer_current_time ) / 2; - - timer_countdown_to_next_gettimeofday = (int64_t) (timer_freq * - SECONDS_BETWEEN_GETTIMEOFDAY_SYNCH); - } - - while (timer != NULL) { - while (timer_current_time >= timer->next_tick_at) { - timer->timer_tick(timer, timer->extra); - timer->next_tick_at += timer->interval; - } - - timer = timer->next; - } - -#ifdef TEST - printf("T"); fflush(stdout); -#endif -} - - -/* - * timer_start(): - * - * Set the interval timer to timer_freq Hz, and install the signal handler. - */ -void timer_start(void) -{ - struct timer *timer = first_timer; - struct itimerval val; - struct sigaction saction; - - if (timer_is_running) - return; - - timer_is_running = 1; - - gettimeofday(&timer_start_tv, NULL); - timer_current_time = 0.0; - - /* Reset all timers: */ - while (timer != NULL) { - timer->next_tick_at = timer->interval; - timer = timer->next; - } - val.it_interval.tv_sec = 0; - val.it_interval.tv_usec = (int) (1000000.0 / timer_freq); - val.it_value.tv_sec = 0; - val.it_value.tv_usec = (int) (1000000.0 / timer_freq); - - memset(&saction, 0, sizeof(saction)); - saction.sa_handler = timer_tick; - saction.sa_flags = SA_RESTART; - - sigaction(SIGALRM, &saction, NULL); - - setitimer(ITIMER_REAL, &val, NULL); -} - - -/* - * timer_stop(): - * - * Deinstall the signal handler, and disable the interval timer. - */ -void timer_stop(void) -{ - struct itimerval val; - struct sigaction saction; - - if (!timer_is_running) - return; - - timer_is_running = 0; - - val.it_interval.tv_sec = 0; - val.it_interval.tv_usec = 0; - val.it_value.tv_sec = 0; - val.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL, &val, NULL); - - memset(&saction, 0, sizeof(saction)); - saction.sa_handler = NULL; - - sigaction(SIGALRM, &saction, NULL); -} - - -#ifdef TEST -static void timer_tick_test(struct timer *t, void *extra) -{ - printf((char *) extra); fflush(stdout); -} -#endif - - -/* - * timer_init(): - * - * Initialize the timer framework. - */ -void timer_init(void) -{ - first_timer = NULL; - timer_current_time = 0.0; - timer_is_running = 0; - timer_countdown_to_next_gettimeofday = 0; - - timer_freq = TIMER_BASE_FREQUENCY; - timer_current_time_step = 1.0 / timer_freq; - -#ifdef TEST - timer_add(0.5, timer_tick_test, "X"); - timer_add(10.0, timer_tick_test, "."); - timer_add(200.0, timer_tick_test, " "); - timer_start(); - while (1) - sleep(999999); -#endif -} - diff -Nru gxemul-0.6.2/src/promemul/arcbios.c gxemul-0.7.0+dfsg/src/promemul/arcbios.c --- gxemul-0.6.2/src/promemul/arcbios.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/arcbios.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,3162 @@ +/* + * Copyright (C) 2003-2021 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: ARCBIOS and ARCS emulation + * + * Some good info here: + * https://www.linux-mips.org/wiki/ARC + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "arcbios.h" +#include "console.h" +#include "cpu.h" +#include "cpu_mips.h" +#include "diskimage.h" +#include "machine.h" +#include "machine_arc.h" +#include "memory.h" +#include "misc.h" + +#include "thirdparty/arcbios_other.h" + + +extern int quiet_mode; +extern int verbose; + + +/* + * arcbios_add_string_to_component(): + */ +void arcbios_add_string_to_component(struct machine *machine, + char *str, uint64_t component) +{ + if (machine->md.arc->n_string_to_components + >= MAX_STRING_TO_COMPONENT) { + printf("Too many string-to-component mappings.\n"); + exit(1); + } + + CHECK_ALLOCATION(machine->md.arc->string_to_component[machine-> + md.arc->n_string_to_components] = strdup(str)); + + debug("adding ARC component mapping: 0x%08x = %s\n", + (int)component, str); + + machine->md.arc->string_to_component_value[ + machine->md.arc->n_string_to_components] = component; + + machine->md.arc->n_string_to_components ++; +} + + +/* + * arcbios_get_dsp_stat(): + * + * Fills in an arcbios_dsp_stat struct with valid data. + */ +static void arcbios_get_dsp_stat(struct cpu *cpu, + struct arcbios_dsp_stat *dspstat) +{ + memset(dspstat, 0, sizeof(struct arcbios_dsp_stat)); + + store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> + CursorXPosition, cpu->machine->md.arc->console_curx + 1); + store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> + CursorYPosition, cpu->machine->md.arc->console_cury + 1); + store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> + CursorMaxXPosition, ARC_CONSOLE_MAX_X); + store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> + CursorMaxYPosition, ARC_CONSOLE_MAX_Y); + dspstat->ForegroundColor = cpu->machine->md.arc->console_curcolor; + dspstat->HighIntensity = cpu->machine->md.arc->console_curcolor ^ 0x08; +} + + +/* + * arcbios_putcell(): + */ +static void arcbios_putcell(struct cpu *cpu, int ch, int x, int y) +{ + unsigned char buf[2]; + buf[0] = ch; + buf[1] = cpu->machine->md.arc->console_curcolor; + if (cpu->machine->md.arc->console_reverse) + buf[1] = ((buf[1] & 0x70) >> 4) | ((buf[1] & 7) << 4) + | (buf[1] & 0x88); + cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc->console_vram + + 2*(x + cpu->machine->md.arc->console_maxx * y), + &buf[0], sizeof(buf), MEM_WRITE, + CACHE_NONE | PHYSICAL); +} + + +/* + * handle_esc_seq(): + * + * Used by arcbios_putchar(). + */ +static void handle_esc_seq(struct cpu *cpu) +{ + int i, len = strlen(cpu->machine->md.arc->escape_sequence); + int row, col, color, code, start, stop; + char *p; + + if (cpu->machine->md.arc->escape_sequence[0] != '[') + return; + + code = cpu->machine->md.arc->escape_sequence[len-1]; + cpu->machine->md.arc->escape_sequence[len-1] = '\0'; + + switch (code) { + case 'm': + color = atoi(cpu->machine->md.arc->escape_sequence + 1); + switch (color) { + case 0: /* Default. */ + cpu->machine->md.arc->console_curcolor = 0x1f; + cpu->machine->md.arc->console_reverse = 0; break; + case 1: /* "Bold". */ + cpu->machine->md.arc->console_curcolor |= 0x08; break; + case 7: /* "Reverse". */ + cpu->machine->md.arc->console_reverse = 1; break; + case 30: /* Black foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x00; break; + case 31: /* Red foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x04; break; + case 32: /* Green foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x02; break; + case 33: /* Yellow foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x06; break; + case 34: /* Blue foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x01; break; + case 35: /* Red-blue foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x05; break; + case 36: /* Green-blue foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x03; break; + case 37: /* White foreground. */ + cpu->machine->md.arc->console_curcolor &= 0xf0; + cpu->machine->md.arc->console_curcolor |= 0x07; break; + case 40: /* Black background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x00; break; + case 41: /* Red background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x40; break; + case 42: /* Green background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x20; break; + case 43: /* Yellow background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x60; break; + case 44: /* Blue background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x10; break; + case 45: /* Red-blue background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x50; break; + case 46: /* Green-blue background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x30; break; + case 47: /* White background. */ + cpu->machine->md.arc->console_curcolor &= 0x0f; + cpu->machine->md.arc->console_curcolor |= 0x70; break; + default:fatal("{ handle_esc_seq: color %i }\n", color); + } + return; + case 'H': + p = strchr(cpu->machine->md.arc->escape_sequence, ';'); + if (p == NULL) + return; /* TODO */ + row = atoi(cpu->machine->md.arc->escape_sequence + 1); + col = atoi(p + 1); + if (col < 1) + col = 1; + if (row < 1) + row = 1; + cpu->machine->md.arc->console_curx = col - 1; + cpu->machine->md.arc->console_cury = row - 1; + return; + case 'J': + /* + * J = clear screen below cursor, and the rest of the + * current line, + * 2J = clear whole screen. + */ + i = atoi(cpu->machine->md.arc->escape_sequence + 1); + if (i != 0 && i != 2) + fatal("{ handle_esc_seq(): %iJ }\n", i); + if (i == 0) + for (col = cpu->machine->md.arc->console_curx; + col < cpu->machine->md.arc->console_maxx; col++) + arcbios_putcell(cpu, ' ', col, + cpu->machine->md.arc->console_cury); + for (col = 0; col < cpu->machine->md.arc->console_maxx; col++) + for (row = i? 0 : cpu->machine->md.arc->console_cury+1; + row < cpu->machine->md.arc->console_maxy; row++) + arcbios_putcell(cpu, ' ', col, row); + return; + case 'K': + col = atoi(cpu->machine->md.arc->escape_sequence + 1); + /* 2 = clear line to the right. 1 = to the left (?) */ + start = 0; stop = cpu->machine->md.arc->console_curx; + if (col == 2) { + start = cpu->machine->md.arc->console_curx; + stop = cpu->machine->md.arc->console_maxx - 1; + } + for (i=start; i<=stop; i++) + arcbios_putcell(cpu, ' ', i, + cpu->machine->md.arc->console_cury); + + return; + } + + fatal("{ handle_esc_seq(): unimplemented escape sequence: "); + for (i=0; imachine->md.arc->escape_sequence[i]; + if (i == len-1) + x = code; + + if (x >= ' ' && x < 127) + fatal("%c", x); + else + fatal("[0x%02x]", x); + } + fatal(" }\n"); +} + + +/* + * scroll_if_necessary(): + */ +static void scroll_if_necessary(struct cpu *cpu) +{ + /* Scroll? */ + if (cpu->machine->md.arc->console_cury >= + cpu->machine->md.arc->console_maxy) { + unsigned char buf[2]; + int x, y; + for (y=0; ymachine->md.arc->console_maxy-1; y++) + for (x=0; xmachine->md.arc->console_maxx; + x++) { + cpu->memory_rw(cpu, cpu->mem, + cpu->machine->md.arc->console_vram + + 2*(x + cpu->machine->md.arc-> + console_maxx * (y+1)), + &buf[0], sizeof(buf), MEM_READ, + CACHE_NONE | PHYSICAL); + cpu->memory_rw(cpu, cpu->mem, + cpu->machine->md.arc->console_vram + + 2*(x + cpu->machine->md.arc-> + console_maxx * y), + &buf[0], sizeof(buf), MEM_WRITE, + CACHE_NONE | PHYSICAL); + } + + cpu->machine->md.arc->console_cury = + cpu->machine->md.arc->console_maxy - 1; + + for (x=0; xmachine->md.arc->console_maxx; x++) + arcbios_putcell(cpu, ' ', x, + cpu->machine->md.arc->console_cury); + } +} + + +/* + * arcbios_putchar(): + * + * If we're using X11 with VGA-style console, then output to that console. + * Otherwise, use console_putchar(). + */ +static void arcbios_putchar(struct cpu *cpu, int ch) +{ + int addr; + unsigned char byte; + + if (!cpu->machine->md.arc->vgaconsole) { + /* Text console output: */ + + /* Hack for Windows NT, which uses 0x9b instead of ESC + [ */ + if (ch == 0x9b) { + console_putchar(cpu->machine->main_console_handle, 27); + ch = '['; + } + console_putchar(cpu->machine->main_console_handle, ch); + return; + } + + if (cpu->machine->md.arc->in_escape_sequence) { + int len = strlen(cpu->machine->md.arc->escape_sequence); + cpu->machine->md.arc->escape_sequence[len] = ch; + len++; + if (len >= ARC_MAX_ESC) + len = ARC_MAX_ESC; + cpu->machine->md.arc->escape_sequence[len] = '\0'; + if ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || len >= ARC_MAX_ESC) { + handle_esc_seq(cpu); + cpu->machine->md.arc->in_escape_sequence = 0; + } + } else { + if (ch == 27) { + cpu->machine->md.arc->in_escape_sequence = 1; + cpu->machine->md.arc->escape_sequence[0] = '\0'; + } else if (ch == 0x9b) { + cpu->machine->md.arc->in_escape_sequence = 1; + cpu->machine->md.arc->escape_sequence[0] = '['; + cpu->machine->md.arc->escape_sequence[1] = '\0'; + } else if (ch == '\b') { + if (cpu->machine->md.arc->console_curx > 0) + cpu->machine->md.arc->console_curx --; + } else if (ch == '\r') { + cpu->machine->md.arc->console_curx = 0; + } else if (ch == '\n') { + cpu->machine->md.arc->console_cury ++; + } else if (ch == '\t') { + cpu->machine->md.arc->console_curx = + ((cpu->machine->md.arc->console_curx - 1) + | 7) + 1; + /* TODO: Print spaces? */ + } else { + /* Put char: */ + if (cpu->machine->md.arc->console_curx >= + cpu->machine->md.arc->console_maxx) { + cpu->machine->md.arc->console_curx = 0; + cpu->machine->md.arc->console_cury ++; + scroll_if_necessary(cpu); + } + arcbios_putcell(cpu, ch, + cpu->machine->md.arc->console_curx, + cpu->machine->md.arc->console_cury); + cpu->machine->md.arc->console_curx ++; + } + } + + scroll_if_necessary(cpu); + + /* Update cursor position: */ + addr = (cpu->machine->md.arc->console_curx >= + cpu->machine->md.arc->console_maxx? + cpu->machine->md.arc->console_maxx - 1 : + cpu->machine->md.arc->console_curx) + + cpu->machine->md.arc->console_cury * + cpu->machine->md.arc->console_maxx; + byte = 0x0e; + cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> + console_ctrlregs + 0x14, + &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); + byte = (addr >> 8) & 255; + cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> + console_ctrlregs + 0x15, + &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); + byte = 0x0f; + cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> + console_ctrlregs + 0x14, + &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); + byte = addr & 255; + cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> + console_ctrlregs + 0x15, + &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); +} + + +/* + * arcbios_putstring(): + */ +static void arcbios_putstring(struct cpu *cpu, const char *s) +{ + while (*s) { + if (*s == '\n') + arcbios_putchar(cpu, '\r'); + arcbios_putchar(cpu, *s++); + } +} + + +/* + * arcbios_register_scsicontroller(): + */ +void arcbios_register_scsicontroller(struct machine *machine, + uint64_t scsicontroller_component) +{ + machine->md.arc->scsicontroller = scsicontroller_component; +} + + +/* + * arcbios_get_scsicontroller(): + */ +uint64_t arcbios_get_scsicontroller(struct machine *machine) +{ + return machine->md.arc->scsicontroller; +} + + +/* + * arcbios_add_memory_descriptor(): + * + * NOTE: arctype is the ARC type, not the SGI type. This function takes + * care of converting, when necessary. + */ +void arcbios_add_memory_descriptor(struct cpu *cpu, + uint64_t base, uint64_t len, int arctype) +{ + uint64_t memdesc_addr; + int s; + struct arcbios_mem arcbios_mem; + struct arcbios_mem64 arcbios_mem64; + + if (verbose >= 2) + debug("arcbios_add_memory_descriptor: base=0x%llx len=0x%llx arctype=%i\n", + (long long)base, (long long)len, arctype); + + base /= 4096; + len /= 4096; + + /* + * TODO: Huh? Why isn't it necessary to convert from arc to sgi types? + * + * TODO 2: It seems that it _is_ necessary, but NetBSD's arcdiag + * doesn't handle the sgi case separately. + */ +#if 1 + if (cpu->machine->machine_type == MACHINE_SGI) { + /* arctype is SGI style */ + /* printf("%i => ", arctype); */ + switch (arctype) { + case 0: arctype = 0; break; + case 1: arctype = 1; break; + case 2: arctype = 3; break; + case 3: arctype = 4; break; + case 4: arctype = 5; break; + case 5: arctype = 6; break; + case 6: arctype = 7; break; + case 7: arctype = 2; break; + } + /* printf("%i\n", arctype); */ + } +#endif + if (cpu->machine->md.arc->arc_64bit) + s = sizeof(arcbios_mem64); + else + s = sizeof(arcbios_mem); + + memdesc_addr = cpu->machine->md.arc->memdescriptor_base + + cpu->machine->md.arc->n_memdescriptors * s; + + if (cpu->machine->md.arc->arc_64bit) { + memset(&arcbios_mem64, 0, s); + store_32bit_word_in_host(cpu, + (unsigned char *)&arcbios_mem64.Type, arctype); + store_64bit_word_in_host(cpu, + (unsigned char *)&arcbios_mem64.BasePage, base); + store_64bit_word_in_host(cpu, + (unsigned char *)&arcbios_mem64.PageCount, len); + store_buf(cpu, memdesc_addr, (char *)&arcbios_mem64, s); + } else { + memset(&arcbios_mem, 0, s); + store_32bit_word_in_host(cpu, + (unsigned char *)&arcbios_mem.Type, arctype); + store_32bit_word_in_host(cpu, + (unsigned char *)&arcbios_mem.BasePage, base); + store_32bit_word_in_host(cpu, + (unsigned char *)&arcbios_mem.PageCount, len); + store_buf(cpu, memdesc_addr, (char *)&arcbios_mem, s); + } + + cpu->machine->md.arc->n_memdescriptors ++; +} + + +/* + * arcbios_addchild(): + * + * host_tmp_component is a temporary component, with data formated for + * the host system. It needs to be translated/copied into emulated RAM. + * + * Return value is the virtual (emulated) address of the added component. + * + * TODO: This function doesn't care about memory management, but simply + * stores the new child after the last stored child. + * TODO: This stuff is really ugly. + */ +static uint64_t arcbios_addchild(struct cpu *cpu, + struct arcbios_component *host_tmp_component, + const char *identifier, uint32_t parent) +{ + struct machine *machine = cpu->machine; + uint64_t a = machine->md.arc->next_component_address; + uint32_t peer=0; + uint32_t child=0; + int n_left; + uint64_t peeraddr = FIRST_ARC_COMPONENT; + + /* + * This component has no children yet, but it may have peers (that is, + * other components that share this component's parent) so we have to + * set the peer value correctly. + * + * Also, if this is the first child of some parent, the parent's child + * pointer should be set to point to this component. (But only if it + * is the first.) + * + * This is really ugly: scan through all components, starting from + * FIRST_ARC_COMPONENT, to find a component with the same parent as + * this component will have. If such a component is found, and its + * 'peer' value is NULL, then set it to this component's address (a). + * + * TODO: make this nicer + */ + + n_left = machine->md.arc->n_components; + while (n_left > 0) { + /* Load parent, child, and peer values: */ + uint32_t eparent, echild, epeer, tmp; + unsigned char buf[4]; + + /* debug("[ addchild: peeraddr = 0x%08x ]\n", + (int)peeraddr); */ + + cpu->memory_rw(cpu, cpu->mem, + peeraddr + 0 * machine->md.arc->wordlen, &buf[0], + sizeof(eparent), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; + tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; + } + epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + + cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * + machine->md.arc->wordlen, + &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; + tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; + } + echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + + cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * + machine->md.arc->wordlen, + &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; + tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; + } + eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + + /* debug(" epeer=%x echild=%x eparent=%x\n", + (int)epeer,(int)echild,(int)eparent); */ + + if ((uint32_t)eparent == (uint32_t)parent && + (uint32_t)epeer == 0) { + epeer = a; + store_32bit_word(cpu, peeraddr + 0x00, epeer); + /* debug("[ addchild: adding 0x%08x as peer " + "to 0x%08x ]\n", (int)a, (int)peeraddr); */ + } + if ((uint32_t)peeraddr == (uint32_t)parent && + (uint32_t)echild == 0) { + echild = a; + store_32bit_word(cpu, peeraddr + 0x04, echild); + /* debug("[ addchild: adding 0x%08x as " + "child to 0x%08x ]\n", (int)a, (int)peeraddr); */ + } + + /* Go to the next component: */ + cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x28, &buf[0], + sizeof(eparent), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; + tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; + } + + tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + peeraddr += 0x30; + peeraddr += tmp + 1; + peeraddr = ((peeraddr - 1) | 3) + 1; + + n_left --; + } + + store_32bit_word(cpu, a + 0x00, peer); + store_32bit_word(cpu, a + 0x04, child); + store_32bit_word(cpu, a + 0x08, parent); + store_32bit_word(cpu, a+ 0x0c, host_tmp_component->Class); + store_32bit_word(cpu, a+ 0x10, host_tmp_component->Type); + store_32bit_word(cpu, a+ 0x14, host_tmp_component->Flags + + 65536 * host_tmp_component->Version); + store_32bit_word(cpu, a+ 0x18, host_tmp_component->Revision); + store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Key); + store_32bit_word(cpu, a+ 0x20, host_tmp_component->AffinityMask); + store_32bit_word(cpu, a+ 0x24, host_tmp_component-> + ConfigurationDataSize); + store_32bit_word(cpu, a+ 0x28, host_tmp_component->IdentifierLength); + store_32bit_word(cpu, a+ 0x2c, host_tmp_component->Identifier); + + machine->md.arc->next_component_address += 0x30; + + if (host_tmp_component->IdentifierLength != 0) { + store_32bit_word(cpu, a + 0x2c, a + 0x30); + store_string(cpu, a + 0x30, identifier); + if (identifier != NULL) + machine->md.arc->next_component_address += + strlen(identifier) + 1; + } + + machine->md.arc->next_component_address ++; + + /* Round up to next 0x4 bytes: */ + machine->md.arc->next_component_address = + ((machine->md.arc->next_component_address - 1) | 3) + 1; + + machine->md.arc->n_components ++; + + return a; +} + + +/* + * arcbios_addchild64(): + * + * host_tmp_component is a temporary component, with data formated for + * the host system. It needs to be translated/copied into emulated RAM. + * + * Return value is the virtual (emulated) address of the added component. + * + * TODO: This function doesn't care about memory management, but simply + * stores the new child after the last stored child. + * TODO: This stuff is really ugly. + */ +static uint64_t arcbios_addchild64(struct cpu *cpu, + struct arcbios_component64 *host_tmp_component, + const char *identifier, uint64_t parent) +{ + struct machine *machine = cpu->machine; + uint64_t a = machine->md.arc->next_component_address; + uint64_t peer=0; + uint64_t child=0; + int n_left; + uint64_t peeraddr = FIRST_ARC_COMPONENT; + + /* + * This component has no children yet, but it may have peers (that is, + * other components that share this component's parent) so we have to + * set the peer value correctly. + * + * Also, if this is the first child of some parent, the parent's child + * pointer should be set to point to this component. (But only if it + * is the first.) + * + * This is really ugly: scan through all components, starting from + * FIRST_ARC_COMPONENT, to find a component with the same parent as + * this component will have. If such a component is found, and its + * 'peer' value is NULL, then set it to this component's address (a). + * + * TODO: make this nicer + */ + + n_left = machine->md.arc->n_components; + while (n_left > 0) { + /* Load parent, child, and peer values: */ + uint64_t eparent, echild, epeer, tmp; + unsigned char buf[8]; + + /* debug("[ addchild: peeraddr = 0x%016" PRIx64" ]\n", + (uint64_t) peeraddr); */ + + cpu->memory_rw(cpu, cpu->mem, + peeraddr + 0 * machine->md.arc->wordlen, &buf[0], + sizeof(eparent), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; + tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; + tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; + tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; + } + epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) + + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) + + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); + + cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * + machine->md.arc->wordlen, + &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; + tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; + tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; + tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; + } + echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) + + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) + + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); + + cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * + machine->md.arc->wordlen, + &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; + tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; + tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; + tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; + } + eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) + + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) + + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); + + /* debug(" epeer=%" PRIx64" echild=%" PRIx64" eparent=%" PRIx64 + "\n", (uint64_t) epeer, (uint64_t) echild, + (uint64_t) eparent); */ + + if (eparent == parent && epeer == 0) { + epeer = a; + store_64bit_word(cpu, peeraddr + 0 * + machine->md.arc->wordlen, epeer); + /* debug("[ addchild: adding 0x%016" PRIx64" as peer " + "to 0x%016" PRIx64" ]\n", (uint64_t) a, + (uint64_t) peeraddr); */ + } + if (peeraddr == parent && echild == 0) { + echild = a; + store_64bit_word(cpu, peeraddr + 1 * + machine->md.arc->wordlen, echild); + /* debug("[ addchild: adding 0x%016" PRIx64" as child " + "to 0x%016" PRIx64" ]\n", (uint64_t) a, + (uint64_t) peeraddr); */ + } + + /* Go to the next component: */ + cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x34, + &buf[0], sizeof(uint32_t), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp2; + tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; + tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; + } + tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); + + tmp &= 0xfffff; + + peeraddr += 0x50; + peeraddr += tmp + 1; + peeraddr = ((peeraddr - 1) | 3) + 1; + + n_left --; + } + + store_64bit_word(cpu, a + 0x00, peer); + store_64bit_word(cpu, a + 0x08, child); + store_64bit_word(cpu, a + 0x10, parent); + store_32bit_word(cpu, a+ 0x18, host_tmp_component->Class); + store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Type); + store_32bit_word(cpu, a+ 0x20, host_tmp_component->Flags); + store_32bit_word(cpu, a+ 0x24, host_tmp_component->Version + + ((uint64_t)host_tmp_component->Revision << 16)); + store_32bit_word(cpu, a+ 0x28, host_tmp_component->Key); + store_64bit_word(cpu, a+ 0x30, host_tmp_component->AffinityMask); + store_64bit_word(cpu, a+ 0x38, host_tmp_component-> + ConfigurationDataSize); + store_64bit_word(cpu, a+ 0x40, host_tmp_component->IdentifierLength); + store_64bit_word(cpu, a+ 0x48, host_tmp_component->Identifier); + + /* TODO: Find out how a REAL ARCS64 implementation does it. */ + + machine->md.arc->next_component_address += 0x50; + + if (host_tmp_component->IdentifierLength != 0) { + store_64bit_word(cpu, a + 0x48, a + 0x50); + store_string(cpu, a + 0x50, identifier); + if (identifier != NULL) + machine->md.arc->next_component_address += + strlen(identifier) + 1; + } + + machine->md.arc->next_component_address ++; + + /* Round up to next 0x8 bytes: */ + machine->md.arc->next_component_address = + ((machine->md.arc->next_component_address - 1) | 7) + 1; + + machine->md.arc->n_components ++; + return a; +} + + +/* + * arcbios_addchild_manual(): + * + * Used internally to set up component structures. + * Parent may only be NULL for the first (system) component. + * + * Return value is the virtual (emulated) address of the added component. + */ +uint64_t arcbios_addchild_manual(struct cpu *cpu, + uint64_t cclass, uint64_t type, uint64_t flags, + uint64_t version, uint64_t revision, uint64_t key, + uint64_t affinitymask, const char *identifier, uint64_t parent, + void *config_data, size_t config_len) +{ + struct machine *machine = cpu->machine; + /* This component is only for temporary use: */ + struct arcbios_component component; + struct arcbios_component64 component64; + + if (config_data != NULL) { + unsigned char *p = (unsigned char *) config_data; + size_t i; + + if (machine->md.arc->n_configuration_data >= MAX_CONFIG_DATA) { + printf("fatal error: you need to increase " + "MAX_CONFIG_DATA\n"); + exit(1); + } + + for (i=0; imemory_rw(cpu, cpu->mem, + machine->md.arc->configuration_data_next_addr + i, + &ch, 1, MEM_WRITE, CACHE_NONE); + } + + machine->md.arc->configuration_data_len[ + machine->md.arc->n_configuration_data] = config_len; + machine->md.arc->configuration_data_configdata[ + machine->md.arc->n_configuration_data] = + machine->md.arc->configuration_data_next_addr; + machine->md.arc->configuration_data_next_addr += config_len; + machine->md.arc->configuration_data_component[ + machine->md.arc->n_configuration_data] = + machine->md.arc->next_component_address + + (cpu->machine->md.arc->arc_64bit? 0x18 : 0x0c); + + /* printf("& ADDING %i: configdata=0x%016" PRIx64" " + "component=0x%016" PRIx64"\n", + machine->md.arc->n_configuration_data, + (uint64_t) machine->md.arc->configuration_data_configdata[ + machine->md.arc->n_configuration_data], + (uint64_t) machine->md.arc->configuration_data_component[ + machine->md.arc->n_configuration_data]); */ + + machine->md.arc->n_configuration_data ++; + } + + if (!cpu->machine->md.arc->arc_64bit) { + component.Class = cclass; + component.Type = type; + component.Flags = flags; + component.Version = version; + component.Revision = revision; + component.Key = key; + component.AffinityMask = affinitymask; + component.ConfigurationDataSize = config_len; + component.IdentifierLength = 0; + component.Identifier = 0; + if (identifier != NULL) { + component.IdentifierLength = strlen(identifier) + 1; + } + + return arcbios_addchild(cpu, &component, identifier, parent); + } else { + component64.Class = cclass; + component64.Type = type; + component64.Flags = flags; + component64.Version = version; + component64.Revision = revision; + component64.Key = key; + component64.AffinityMask = affinitymask; + component64.ConfigurationDataSize = config_len; + component64.IdentifierLength = 0; + component64.Identifier = 0; + if (identifier != NULL) { + component64.IdentifierLength = strlen(identifier) + 1; + } + + return arcbios_addchild64(cpu, &component64, identifier, + parent); + } +} + + +/* + * arcbios_get_msdos_partition_size(): + * + * This function tries to parse MSDOS-style partition tables on a disk + * image, and return the starting offset (counted in bytes), and the + * size, of a specific partition. + * + * NOTE: partition_nr is 1-based! + * + * TODO: This is buggy, it doesn't really handle extended partitions. + * + * See http://www.nondot.org/sabre/os/files/Partitions/Partitions.html + * for more info. + */ +static void arcbios_get_msdos_partition_size(struct machine *machine, + int disk_id, int disk_type, int partition_nr, uint64_t *start, + uint64_t *size) +{ + int res, i, partition_type, cur_partition = 0; + unsigned char sector[512]; + unsigned char buf[16]; + uint64_t offset = 0, st; + + /* Partition 0 is the entire disk image: */ + *start = 0; + *size = diskimage_getsize(machine, disk_id, disk_type); + if (partition_nr == 0) + return; + +ugly_goto: + *start = 0; *size = 0; + + /* printf("reading MSDOS partition from offset 0x%" PRIx64"\n", + (uint64_t) offset); */ + + res = diskimage_access(machine, disk_id, disk_type, 0, offset, + sector, sizeof(sector)); + if (!res) { + fatal("[ arcbios_get_msdos_partition_size(): couldn't " + "read the disk image, id %i, offset 0x%" PRIx64" ]\n", + disk_id, (uint64_t) offset); + return; + } + + if (sector[510] != 0x55 || sector[511] != 0xaa) { + fatal("[ arcbios_get_msdos_partition_size(): not an " + "MSDOS partition table ]\n"); + } + +#if 0 + /* Debug dump: */ + for (i=0; i<4; i++) { + int j; + printf(" partition %i: ", i+1); + for (j=0; j<16; j++) + printf(" %02x", sector[446 + i*16 + j]); + printf("\n"); + } +#endif + + for (i=0; i<4; i++) { + memmove(buf, sector + 446 + 16*i, 16); + + partition_type = buf[4]; + + if (partition_type == 0) + continue; + + st = (buf[8] + (buf[9] << 8) + (buf[10] << 16) + + (buf[11] << 24)) * 512; + + if (start != NULL) + *start = st; + if (size != NULL) + *size = (buf[12] + (buf[13] << 8) + (buf[14] << 16) + + (buf[15] << 24)) * 512; + + /* Extended DOS partition: */ + if (partition_type == 5) { + offset += st; + goto ugly_goto; + } + + /* Found the right partition? Then return. */ + cur_partition ++; + if (cur_partition == partition_nr) + return; + } + + fatal("[ partition(%i) NOT found ]\n", partition_nr); +} + + +/* + * arcbios_handle_to_disk_id_and_type(): + */ +static int arcbios_handle_to_disk_id_and_type(struct machine *machine, int handle, int *typep) +{ + const char *s; + + if (handle < 0 || handle >= ARC_MAX_HANDLES) + return -1; + + s = machine->md.arc->file_handle_string[handle]; + if (s == NULL) + return -1; + + /* + * s is something like "scsi(0)disk(0)rdisk(0)partition(0)". + * TODO: This is really ugly and hardcoded. + */ + + if (strncmp(s, "pci(0)", 6) == 0) + s += 6; + + if (strncmp(s, "scsi(0)", 7) == 0) { + *typep = DISKIMAGE_SCSI; + s += 7; + } else { + return -1; + } + + if (strncmp(s, "disk(", 5) == 0) { + return atoi(s + 5); + } + + if (strncmp(s, "cdrom(", 6) == 0) { + return atoi(s + 6); + } + + return -1; +} + + +/* + * arcbios_handle_to_start_and_size(): + */ +static void arcbios_handle_to_start_and_size(struct machine *machine, + int handle, uint64_t *start, uint64_t *size) +{ + const char *s = machine->md.arc->file_handle_string[handle]; + const char *s2; + int disk_id, disk_type; + + disk_id = arcbios_handle_to_disk_id_and_type(machine, handle, &disk_type); + + if (disk_id < 0) + return; + + // Default to "full disk": + *start = 0; + *size = diskimage_getsize(machine, disk_id, disk_type); + + if (machine->machine_type == MACHINE_SGI) { + /* + * TODO: + * + * Read the SGI volume header / disk label. e.g.: + * + * partitions: + * partition 0: 592820 blocks at 4096 (type 4) + * partition 8: 4096 blocks at 0 (type 0) + * partition 10: 596916 blocks at 0 (type 6) + * + * Warn about accessing partitions that are not specified + * with a size > 0. + */ + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_WARNING, "TODO: sgi partition"); + return; + } + + s2 = strstr(s, "partition("); + if (s2 != NULL) { + int partition_nr = atoi(s2 + 10); + /* printf("partition_nr = %i\n", partition_nr); */ + if (partition_nr != 0) + arcbios_get_msdos_partition_size(machine, + disk_id, disk_type, partition_nr, start, size); + } +} + + +/* + * arcbios_getfileinformation(): + * + * Fill in a GetFileInformation struct in emulated memory, + * for a specific file handle. (This is used to get the size + * and offsets of partitions on disk images.) + */ +static int arcbios_getfileinformation(struct cpu *cpu) +{ + int handle = cpu->cd.mips.gpr[MIPS_GPR_A0]; + uint64_t addr = cpu->cd.mips.gpr[MIPS_GPR_A1]; + uint64_t start, size; + + arcbios_handle_to_start_and_size(cpu->machine, handle, &start, &size); + + store_64bit_word(cpu, addr + 0, 0); + store_64bit_word(cpu, addr + 8, size); + store_64bit_word(cpu, addr + 16, 0); + store_32bit_word(cpu, addr + 24, 1); + store_32bit_word(cpu, addr + 28, 0); + store_32bit_word(cpu, addr + 32, 0); + + /* printf("\n!!! size=0x%x start=0x%x\n", (int)size, (int)start); */ + + return ARCBIOS_ESUCCESS; +} + + +/* + * arcbios_private_emul(): + * + * The "normal" vector entries are probably from the ARC standard, whereas + * the "private" entries are unknown SGI specific entries. In the emulator, + * these are dummy implementations, just enough to fool IRIX to continue + * past these calls. + * + * These names are guesses based on symbols on the callstack when "sash" + * calls these entries, perhaps the real function is something completely + * different. + * + * 0x00 ioctl (?) + * 0x04 get nvram table (?) + * 0x14 fs_register (?) + * 0x1c Signal (?) + * 0x20 initGfxGui (?) + * 0x24 sgivers (get version?) + * 0x30 cpufreq (?) + */ +void arcbios_sgi_emul(struct cpu *cpu) +{ + int vector = cpu->pc & 0xfff; + + switch (vector) { + + case 0x00: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_WARNING, "SGI: ioctl? TODO"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; +/* + case 0x04: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_WARNING, "SGI: get nvram table(): TODO"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; +*/ + case 0x14: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_WARNING, "SGI: fs_register? TODO"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + + case 0x1c: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_WARNING, "SGI: Signal? TODO"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + + case 0x20: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_WARNING, "SGI: initGfxGui? TODO"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + + case 0x24: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_WARNING, "SGI: sgivers? TODO"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + + case 0x30: + // This value is displayed by hinv (in sash) as "Processor: xxx MHz" + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "SGI: cpufreq"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 175; + break; + + default: + cpu_register_dump(cpu->machine, cpu, 1, 0x1); + debug("a0 points to: "); + dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); + debug("\n"); + fatal("ARCBIOS: unimplemented SGI vector 0x%x\n", vector); + cpu->running = 0; + } +} + + +/* + * arcbios_emul(): ARCBIOS emulation + * + * 0x0c Halt() + * 0x10 PowerDown() + * 0x14 Restart() + * 0x18 Reboot() + * 0x1c EnterInteractiveMode() + * 0x20 ReturnFromMain() + * 0x24 GetPeer(node) + * 0x28 GetChild(node) + * 0x2c GetParent(node) + * 0x30 GetConfigurationData(config_data, node) + * 0x3c GetComponent(name) + * 0x44 GetSystemId() + * 0x48 GetMemoryDescriptor(void *) + * 0x50 GetTime() + * 0x54 GetRelativeTime() + * 0x5c Open(path, mode, &fileid) + * 0x60 Close(handle) + * 0x64 Read(handle, &buf, len, &actuallen) + * 0x6c Write(handle, buf, len, &returnlen) + * 0x70 Seek(handle, &offset, len) + * 0x78 GetEnvironmentVariable(char *) + * 0x7c SetEnvironmentVariable(char *, char *) + * 0x80 GetFileInformation(handle, buf) + * 0x88 FlushAllCaches() + * 0x90 GetDisplayStatus(uint32_t handle) + * 0x100 undocumented IRIX (?) + */ +int arcbios_emul(struct cpu *cpu) +{ + struct machine *machine = cpu->machine; + int vector = cpu->pc & 0xfff; + int i, j, handle; + unsigned char ch2; + unsigned char buf[40]; + + if (cpu->pc >= ARC_PRIVATE_ENTRIES && + cpu->pc < ARC_PRIVATE_ENTRIES + 100*sizeof(uint32_t)) { + if (machine->machine_type == MACHINE_SGI) + arcbios_sgi_emul(cpu); + else { + fatal("[ ARCBIOS private call for non-SGI. ]\n"); + exit(1); + } + + return 1; + } + + if (machine->md.arc->arc_64bit) + vector /= 2; + + /* Special case for reboot by jumping to 0xbfc00000: */ + if (vector == 0 && (cpu->pc & 0xffffffffULL) == 0xbfc00000ULL) + vector = 0x18; + + switch (vector) { + case 0x0c: /* Halt() */ + case 0x10: /* PowerDown() */ + case 0x14: /* Restart() */ + case 0x18: /* Reboot() */ + case 0x1c: /* EnterInteractiveMode() */ + case 0x20: /* ReturnFromMain() */ + switch (vector) { + case 0x0c: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "Halt()"); + break; + case 0x10: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "PowerDown()"); + break; + case 0x14: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "Restart()"); + break; + case 0x18: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "Reboot()"); + break; + case 0x1c: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "EnterInteractiveMode()"); + break; + case 0x20: + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "ReturnFromMain()"); + break; + } + + /* Halt all CPUs. */ + for (i=0; incpus; i++) { + machine->cpus[i]->running = 0; + } + + break; + case 0x24: /* GetPeer(node) */ + if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { + /* NULL ptr argument: return NULL. */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + } else { + uint64_t peer; + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A0] - 3 * + machine->md.arc->wordlen, &buf[0], + machine->md.arc->wordlen, MEM_READ, CACHE_NONE); + if (machine->md.arc->arc_64bit) { + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp; tmp = buf[0]; + buf[0] = buf[7]; buf[7] = tmp; + tmp = buf[1]; buf[1] = buf[6]; + buf[6] = tmp; + tmp = buf[2]; buf[2] = buf[5]; + buf[5] = tmp; + tmp = buf[3]; buf[3] = buf[4]; + buf[4] = tmp; + } + peer = (uint64_t)buf[0] + ((uint64_t)buf[1]<<8) + + ((uint64_t)buf[2]<<16) + + ((uint64_t)buf[3]<<24) + + ((uint64_t)buf[4]<<32) + + ((uint64_t)buf[5]<<40) + + ((uint64_t)buf[6]<<48) + + ((uint64_t)buf[7]<<56); + } else { + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp; tmp = buf[0]; + buf[0] = buf[3]; buf[3] = tmp; + tmp = buf[1]; buf[1] = buf[2]; + buf[2] = tmp; + } + peer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + + (buf[3]<<24); + } + + cpu->cd.mips.gpr[MIPS_GPR_V0] = peer? + (peer + 3 * machine->md.arc->wordlen) : 0; + if (!machine->md.arc->arc_64bit) + cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) + (int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; + } + debug("[ ARCBIOS GetPeer(node 0x%016" PRIx64"): 0x%016" PRIx64 + " ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); + break; + case 0x28: /* GetChild(node) */ + /* 0 for the root, non-0 for children: */ + if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) + cpu->cd.mips.gpr[MIPS_GPR_V0] = FIRST_ARC_COMPONENT + + machine->md.arc->wordlen * 3; + else { + uint64_t child = 0; + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A0] - 2 * + machine->md.arc->wordlen, &buf[0], machine-> + md.arc->wordlen, MEM_READ, CACHE_NONE); + if (machine->md.arc->arc_64bit) { + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp; tmp = buf[0]; + buf[0] = buf[7]; buf[7] = tmp; + tmp = buf[1]; buf[1] = buf[6]; + buf[6] = tmp; + tmp = buf[2]; buf[2] = buf[5]; + buf[5] = tmp; + tmp = buf[3]; buf[3] = buf[4]; + buf[4] = tmp; + } + child = (uint64_t)buf[0] + + ((uint64_t)buf[1]<<8) + + ((uint64_t)buf[2]<<16) + + ((uint64_t)buf[3]<<24) + + ((uint64_t)buf[4]<<32) + + ((uint64_t)buf[5]<<40) + + ((uint64_t)buf[6]<<48) + + ((uint64_t)buf[7]<<56); + } else { + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp; tmp = buf[0]; + buf[0] = buf[3]; buf[3] = tmp; + tmp = buf[1]; buf[1] = buf[2]; + buf[2] = tmp; + } + child = buf[0] + (buf[1]<<8) + (buf[2]<<16) + + (buf[3]<<24); + } + + cpu->cd.mips.gpr[MIPS_GPR_V0] = child? + (child + 3 * machine->md.arc->wordlen) : 0; + if (!machine->md.arc->arc_64bit) + cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) + (int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0]; + } + debug("[ ARCBIOS GetChild(node 0x%016" PRIx64"): 0x%016" + PRIx64" ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); + break; + case 0x2c: /* GetParent(node) */ + { + uint64_t parent; + + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A0] - 1 * machine-> + md.arc->wordlen, &buf[0], machine->md.arc->wordlen, + MEM_READ, CACHE_NONE); + + if (machine->md.arc->arc_64bit) { + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp; tmp = buf[0]; + buf[0] = buf[7]; buf[7] = tmp; + tmp = buf[1]; buf[1] = buf[6]; + buf[6] = tmp; + tmp = buf[2]; buf[2] = buf[5]; + buf[5] = tmp; + tmp = buf[3]; buf[3] = buf[4]; + buf[4] = tmp; + } + parent = (uint64_t)buf[0] + + ((uint64_t)buf[1]<<8) + + ((uint64_t)buf[2]<<16) + + ((uint64_t)buf[3]<<24) + + ((uint64_t)buf[4]<<32) + + ((uint64_t)buf[5]<<40) + + ((uint64_t)buf[6]<<48) + + ((uint64_t)buf[7]<<56); + } else { + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp; tmp = buf[0]; + buf[0] = buf[3]; buf[3] = tmp; + tmp = buf[1]; buf[1] = buf[2]; + buf[2] = tmp; + } + parent = buf[0] + (buf[1]<<8) + + (buf[2]<<16) + (buf[3]<<24); + } + + cpu->cd.mips.gpr[MIPS_GPR_V0] = parent? + (parent + 3 * machine->md.arc->wordlen) : 0; + if (!machine->md.arc->arc_64bit) + cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) + (int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; + } + debug("[ ARCBIOS GetParent(node 0x%016" PRIx64"): 0x%016" + PRIx64" ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); + break; + case 0x30: /* GetConfigurationData(void *configdata, void *node) */ + /* fatal("[ ARCBIOS GetConfigurationData(0x%016" PRIx64"," + "0x%016" PRIx64") ]\n", + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; + for (i=0; imd.arc->n_configuration_data; i++) { + /* fatal("configuration_data_component[%i] = " + "0x%016" PRIx64"\n", i, (uint64_t) machine-> + md.arc->configuration_data_component[i]); */ + if (cpu->cd.mips.gpr[MIPS_GPR_A1] == + machine->md.arc->configuration_data_component[i]) { + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + for (j=0; j + md.arc->configuration_data_len[i]; j++) { + unsigned char ch; + cpu->memory_rw(cpu, cpu->mem, + machine->md.arc-> + configuration_data_configdata[i] + + j, &ch, 1, MEM_READ, CACHE_NONE); + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A0] + j, + &ch, 1, MEM_WRITE, CACHE_NONE); + } + break; + } + } + break; + case 0x3c: /* GetComponent(char *name) */ + debug("[ ARCBIOS GetComponent(\""); + dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); + debug("\") ]\n"); + + if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { + fatal("[ ARCBIOS GetComponent: NULL ptr ]\n"); + } else { + unsigned char buf2[500]; + int match_index = -1; + int match_len = 0; + + memset(buf2, 0, sizeof(buf2)); + for (i=0; i<(ssize_t)sizeof(buf2); i++) { + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A0] + i, + &buf2[i], 1, MEM_READ, CACHE_NONE); + if (buf2[i] == '\0') + i = sizeof(buf); + } + buf2[sizeof(buf2) - 1] = '\0'; + + /* "scsi(0)disk(0)rdisk(0)partition(0)" and such. */ + /* printf("GetComponent(\"%s\")\n", buf2); */ + + /* Default to NULL return value. */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + + /* Scan the string to component table: */ + for (i=0; imd.arc->n_string_to_components; + i++) { + int m = 0; + while (buf2[m] && machine->md.arc-> + string_to_component[i][m] && + machine->md.arc->string_to_component[i][m] + == buf2[m]) + m++; + if (m > match_len) { + match_len = m; + match_index = i; + } + } + + if (match_index >= 0) { + /* printf("Longest match: '%s'\n", + machine->md.arc->string_to_component[ + match_index]); */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = + machine->md.arc->string_to_component_value[ + match_index]; + } + } + break; + case 0x44: /* GetSystemId() */ + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "GetSystemId()"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = SGI_SYSID_ADDR; + break; + case 0x48: /* void *GetMemoryDescriptor(void *ptr) */ + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "GetMemoryDescriptor(0x%08x)", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + + /* If a0=NULL, then return the first descriptor: */ + if ((uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) + cpu->cd.mips.gpr[MIPS_GPR_V0] = + machine->md.arc->memdescriptor_base; + else { + int s = machine->md.arc->arc_64bit? + sizeof(struct arcbios_mem64) + : sizeof(struct arcbios_mem); + int nr = cpu->cd.mips.gpr[MIPS_GPR_A0] - + machine->md.arc->memdescriptor_base; + nr /= s; + nr ++; + cpu->cd.mips.gpr[MIPS_GPR_V0] = + machine->md.arc->memdescriptor_base + s * nr; + if (nr >= machine->md.arc->n_memdescriptors) + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + } + break; + case 0x50: /* GetTime() */ + debug("[ ARCBIOS GetTime() ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0xffffffff80001000ULL; + /* TODO! */ + break; + case 0x54: /* GetRelativeTime() */ + debug("[ ARCBIOS GetRelativeTime() ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t)time(NULL); + break; + case 0x5c: /* Open(char *path, uint32_t mode, uint32_t *fileID) */ + debug("[ ARCBIOS Open(\""); + dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); + debug("\",0x%x,0x%x)", (int)cpu->cd.mips.gpr[MIPS_GPR_A0], + (int)cpu->cd.mips.gpr[MIPS_GPR_A1], + (int)cpu->cd.mips.gpr[MIPS_GPR_A2]); + + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ENOENT; + + handle = 3; + /* TODO: Starting at 0 would require some updates... */ + while (machine->md.arc->file_handle_in_use[handle]) { + handle ++; + if (handle >= ARC_MAX_HANDLES) { + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EMFILE; + break; + } + } + + if (handle >= ARC_MAX_HANDLES) { + fatal("[ ARCBIOS Open: out of file handles ]\n"); + } else if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { + fatal("[ ARCBIOS Open: NULL ptr ]\n"); + } else { + /* + * TODO: This is hardcoded to successfully open + * anything. It is used by the Windows NT SETUPLDR + * program to load stuff from the boot partition. + */ + unsigned char *buf2; + CHECK_ALLOCATION(buf2 = (unsigned char *) malloc(MAX_OPEN_STRINGLEN)); + memset(buf2, 0, MAX_OPEN_STRINGLEN); + for (i=0; imemory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A0] + i, + &buf2[i], 1, MEM_READ, CACHE_NONE); + if (buf2[i] == '\0') + i = MAX_OPEN_STRINGLEN; + } + buf2[MAX_OPEN_STRINGLEN - 1] = '\0'; + machine->md.arc->file_handle_string[handle] = + (char *)buf2; + machine->md.arc->current_seek_offset[handle] = 0; + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; + } + + if (cpu->cd.mips.gpr[MIPS_GPR_V0] == ARCBIOS_ESUCCESS) { + debug(" = handle %i ]\n", (int)handle); + store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A2], + handle); + machine->md.arc->file_handle_in_use[handle] = 1; + } else + debug(" = ERROR %i ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_V0]); + break; + case 0x60: /* Close(uint32_t handle) */ + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "Close(%i)", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + if (!machine->md.arc->file_handle_in_use[cpu->cd.mips.gpr[ + MIPS_GPR_A0]]) { + fatal("ARCBIOS Close(%i): bad handle\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; + } else { + machine->md.arc->file_handle_in_use[ + cpu->cd.mips.gpr[MIPS_GPR_A0]] = 0; + // TODO: Yes, this is a memory leak. But it will be + // scrapped in favor of real code after the rewrite (I + // hope). + //if (machine->md.arc->file_handle_string[ + // cpu->cd.mips.gpr[MIPS_GPR_A0]] != NULL) + // free(machine->md.arc->file_handle_string[ + // cpu->cd.mips.gpr[MIPS_GPR_A0]]); + machine->md.arc->file_handle_string[cpu->cd.mips. + gpr[MIPS_GPR_A0]] = NULL; + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; + } + break; + case 0x64: /* Read(handle, void *buf, length, uint32_t *count) */ + if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { + int j2, nread = 0, a2; + + /* + * Before going into the loop, make sure stdout + * is flushed. If we're using an X11 VGA console, + * then it needs to be flushed as well. + */ + fflush(stdin); + fflush(stdout); + /* NOTE/TODO: This gives a tick to _everything_ */ + for (j2=0; j2tick_functions.n_entries; j2++) + machine->tick_functions.f[j2](cpu, + machine->tick_functions.extra[j2]); + + a2 = cpu->cd.mips.gpr[MIPS_GPR_A2]; + for (j2=0; j2main_console_handle); + if (x < 0) + return 0; + + /* + * ESC + '[' should be transformed into 0x9b: + * + * NOTE/TODO: This makes the behaviour of just + * pressing ESC a bit harder to define. + */ + if (x == 27) { + x = console_readchar(cpu-> + machine->main_console_handle); + if (x == '[' || x == 'O') + x = 0x9b; + } + + ch = x; + nread ++; + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A1] + j2, + &ch, 1, MEM_WRITE, CACHE_NONE); + + /* NOTE: Only one char, from STDIN: */ + j2 = cpu->cd.mips.gpr[MIPS_GPR_A2]; /* :-) */ + } + + store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], + nread); + /* TODO: not EAGAIN? */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = + nread? ARCBIOS_ESUCCESS: ARCBIOS_EAGAIN; + } else { + int handleTmp = cpu->cd.mips.gpr[MIPS_GPR_A0]; + int disk_type = 0; + int disk_id = arcbios_handle_to_disk_id_and_type( + machine, handleTmp, &disk_type); + uint64_t partition_offset = 0; + int res; + uint64_t size; /* dummy */ + unsigned char *tmp_buf; + + arcbios_handle_to_start_and_size(machine, handleTmp, + &partition_offset, &size); + + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "Read(%i,0x%08x,0x%08x,0x%08x)", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0], + (int)cpu->cd.mips.gpr[MIPS_GPR_A1], + (int)cpu->cd.mips.gpr[MIPS_GPR_A2], + (int)cpu->cd.mips.gpr[MIPS_GPR_A3]); + + CHECK_ALLOCATION(tmp_buf = (unsigned char *) + malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); + + res = diskimage_access(machine, disk_id, disk_type, + 0, partition_offset + machine->md.arc-> + current_seek_offset[handleTmp], tmp_buf, + cpu->cd.mips.gpr[MIPS_GPR_A2]); + + /* If the transfer was successful, transfer the + data to emulated memory: */ + if (res) { + uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; + store_buf(cpu, dst, (char *)tmp_buf, + cpu->cd.mips.gpr[MIPS_GPR_A2]); + store_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A3], + cpu->cd.mips.gpr[MIPS_GPR_A2]); + machine->md.arc->current_seek_offset[handleTmp] += + cpu->cd.mips.gpr[MIPS_GPR_A2]; + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + } else { + debug("[ ... res = %i ]\n", res); + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; + } + free(tmp_buf); + } + break; + case 0x68: /* GetReadStatus(handle) */ + /* + * According to arcbios_tty_getchar() in NetBSD's + * dev/arcbios/arcbios_tty.c, GetReadStatus should + * return 0 if there is something available. + * + * TODO: Error codes are things like ARCBIOS_EAGAIN. + */ + if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { + cpu->cd.mips.gpr[MIPS_GPR_V0] = console_charavail( + machine->main_console_handle)? 0 : 1; + } else { + fatal("[ ARCBIOS GetReadStatus(%i) from " + "something other than STDIN: TODO ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + /* TODO */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; + } + break; + case 0x6c: /* Write(handle, buf, len, &returnlen) */ + if (cpu->cd.mips.gpr[MIPS_GPR_A0] != ARCBIOS_STDOUT) { + /* + * TODO: this is just a test + */ + int handleTmp = cpu->cd.mips.gpr[MIPS_GPR_A0]; + int disk_type = 0; + int disk_id = arcbios_handle_to_disk_id_and_type( + machine, handleTmp, &disk_type); + uint64_t partition_offset = 0; + int res, tmpi; + uint64_t size; /* dummy */ + unsigned char *tmp_buf; + + arcbios_handle_to_start_and_size(machine, + handleTmp, &partition_offset, &size); + + debug("[ ARCBIOS Write(%i,0x%08" PRIx64",%i,0x%08" + PRIx64") ]\n", (int) cpu->cd.mips.gpr[MIPS_GPR_A0], + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1], + (int) cpu->cd.mips.gpr[MIPS_GPR_A2], + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A3]); + + CHECK_ALLOCATION(tmp_buf = (unsigned char *) + malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); + + for (tmpi=0; tmpi<(int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]; tmpi++) + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A1] + tmpi, + &tmp_buf[tmpi], sizeof(char), MEM_READ, + CACHE_NONE); + + res = diskimage_access(machine, disk_id, disk_type, + 1, partition_offset + machine->md.arc-> + current_seek_offset[handleTmp], tmp_buf, + cpu->cd.mips.gpr[MIPS_GPR_A2]); + + if (res) { + store_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A3], + cpu->cd.mips.gpr[MIPS_GPR_A2]); + machine->md.arc->current_seek_offset[handleTmp] += + cpu->cd.mips.gpr[MIPS_GPR_A2]; + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + } else + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; + free(tmp_buf); + } else { + for (i=0; i<(int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]; + i++) { + unsigned char ch = '\0'; + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A1] + i, + &ch, sizeof(ch), MEM_READ, CACHE_NONE); + + arcbios_putchar(cpu, ch); + } + } + store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], + cpu->cd.mips.gpr[MIPS_GPR_A2]); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ + break; + case 0x70: /* Seek(uint32_t handle, int64_t *ofs, + uint32_t whence): uint32_t */ + debug("[ ARCBIOS Seek(%i,0x%08" PRIx64",%i): ", + (int) cpu->cd.mips.gpr[MIPS_GPR_A0], + (uint64_t)cpu->cd.mips.gpr[MIPS_GPR_A1], + (int) cpu->cd.mips.gpr[MIPS_GPR_A2]); + + if (cpu->cd.mips.gpr[MIPS_GPR_A2] != 0) { + fatal("[ ARCBIOS Seek(%i,0x%08" PRIx64",%i): " + "UNIMPLEMENTED whence=%i ]\n", + (int) cpu->cd.mips.gpr[MIPS_GPR_A0], + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1], + (int) cpu->cd.mips.gpr[MIPS_GPR_A2], + (int) cpu->cd.mips.gpr[MIPS_GPR_A2]); + } + + { + unsigned char bufTmp[8]; + uint64_t ofs; + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A1], &bufTmp[0], + sizeof(bufTmp), MEM_READ, CACHE_NONE); + if (cpu->byte_order == EMUL_BIG_ENDIAN) { + unsigned char tmp; + tmp = bufTmp[0]; bufTmp[0] = bufTmp[7]; bufTmp[7] = tmp; + tmp = bufTmp[1]; bufTmp[1] = bufTmp[6]; bufTmp[6] = tmp; + tmp = bufTmp[2]; bufTmp[2] = bufTmp[5]; bufTmp[5] = tmp; + tmp = bufTmp[3]; bufTmp[3] = bufTmp[4]; bufTmp[4] = tmp; + } + ofs = bufTmp[0] + (bufTmp[1] << 8) + (bufTmp[2] << 16) + + (bufTmp[3] << 24) + ((uint64_t)bufTmp[4] << 32) + + ((uint64_t)bufTmp[5] << 40) + ((uint64_t)bufTmp[6] << 48) + + ((uint64_t)bufTmp[7] << 56); + + machine->md.arc->current_seek_offset[ + cpu->cd.mips.gpr[MIPS_GPR_A0]] = ofs; + debug("%016" PRIx64" ]\n", (uint64_t) ofs); + } + + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ + + break; + case 0x78: /* GetEnvironmentVariable(char *) */ + /* Find the environment variable given by a0: */ + for (i=0; i<(ssize_t)sizeof(buf); i++) + cpu->memory_rw(cpu, cpu->mem, + cpu->cd.mips.gpr[MIPS_GPR_A0] + i, + &buf[i], sizeof(char), MEM_READ, CACHE_NONE); + buf[sizeof(buf)-1] = '\0'; + debugmsg(SUBSYS_PROMEMUL, "arcbios", VERBOSITY_DEBUG, "GetEnvironmentVariable(\"%s\")", buf); + for (i=0; i<0x1000; i++) { + /* Matching string at offset i? */ + int nmatches = 0; + uint64_t envptr = machine->machine_type == MACHINE_SGI ? ARC_ENV_STRINGS_SGI : ARC_ENV_STRINGS; + for (j=0; j<(ssize_t)strlen((char *)buf); j++) { + cpu->memory_rw(cpu, cpu->mem, + (uint64_t)(envptr + i + j), + &ch2, sizeof(char), MEM_READ, CACHE_NONE); + if (ch2 == buf[j]) + nmatches++; + } + cpu->memory_rw(cpu, cpu->mem, + (uint64_t)(envptr + i + + strlen((char *)buf)), &ch2, sizeof(char), + MEM_READ, CACHE_NONE); + if (nmatches == (int)strlen((char *)buf) && ch2=='=') { + cpu->cd.mips.gpr[MIPS_GPR_V0] = + envptr + i + + strlen((char *)buf) + 1; + return 1; + } + } + /* Return NULL if string wasn't found. */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x7c: /* SetEnvironmentVariable(char *, char *) */ + debug("[ ARCBIOS SetEnvironmentVariable(\""); + dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); + debug("\",\""); + dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1]); + debug("\") ]\n"); + /* TODO: This is a dummy. */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; + break; + case 0x80: /* GetFileInformation() */ + debug("[ ARCBIOS GetFileInformation(%i,0x%x): ", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0], + (int)cpu->cd.mips.gpr[MIPS_GPR_A1]); + + if (cpu->cd.mips.gpr[MIPS_GPR_A0] >= ARC_MAX_HANDLES) { + debug("invalid file handle ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; + } else if (!machine->md.arc->file_handle_in_use[cpu->cd. + mips.gpr[MIPS_GPR_A0]]) { + debug("file handle not in use! ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; + } else { + debug("'%s' ]\n", machine->md.arc->file_handle_string[ + cpu->cd.mips.gpr[MIPS_GPR_A0]]); + cpu->cd.mips.gpr[MIPS_GPR_V0] = + arcbios_getfileinformation(cpu); + } + break; + case 0x88: /* FlushAllCaches() */ + debug("[ ARCBIOS FlushAllCaches(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x90: /* void *GetDisplayStatus(handle) */ + debug("[ ARCBIOS GetDisplayStatus(%i) ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + /* TODO: handle different values of 'handle'? */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = ARC_DSPSTAT_ADDR; + break; + case 0x100: + /* + * Undocumented, used by IRIX. + */ + debug("[ ARCBIOS: IRIX 0x100 (?) ]\n"); + /* TODO */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x888: + /* + * Magical crash if there is no exception handling code. + */ + fatal("EXCEPTION, but no exception handler installed yet.\n"); + quiet_mode = 0; + cpu_register_dump(machine, cpu, 1, 0x1); + cpu->running = 0; + break; + default: + quiet_mode = 0; + cpu_register_dump(machine, cpu, 1, 0x1); + debug("a0 points to: "); + dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); + debug("\n"); + fatal("ARCBIOS: unimplemented vector 0x%x\n", vector); + cpu->running = 0; + } + + return 1; +} + + +/* + * arcbios_set_default_exception_handler(): + */ +void arcbios_set_default_exception_handler(struct cpu *cpu) +{ + /* + * The default exception handlers simply jump to 0xbfc88888, + * which is then taken care of in arcbios_emul() above. + * + * 3c1abfc8 lui k0,0xbfc8 + * 375a8888 ori k0,k0,0x8888 + * 03400008 jr k0 + * 00000000 nop + */ + store_32bit_word(cpu, 0xffffffff80000000ULL, 0x3c1abfc8); + store_32bit_word(cpu, 0xffffffff80000004ULL, 0x375a8888); + store_32bit_word(cpu, 0xffffffff80000008ULL, 0x03400008); + store_32bit_word(cpu, 0xffffffff8000000cULL, 0x00000000); + + store_32bit_word(cpu, 0xffffffff80000080ULL, 0x3c1abfc8); + store_32bit_word(cpu, 0xffffffff80000084ULL, 0x375a8888); + store_32bit_word(cpu, 0xffffffff80000088ULL, 0x03400008); + store_32bit_word(cpu, 0xffffffff8000008cULL, 0x00000000); + + store_32bit_word(cpu, 0xffffffff80000180ULL, 0x3c1abfc8); + store_32bit_word(cpu, 0xffffffff80000184ULL, 0x375a8888); + store_32bit_word(cpu, 0xffffffff80000188ULL, 0x03400008); + store_32bit_word(cpu, 0xffffffff8000018cULL, 0x00000000); +} + + +/* + * arcbios_add_other_components(): + * + * TODO: How should this be synched with the hardware devices + * added in machine.c? + */ +static void arcbios_add_other_components(struct machine *machine, + uint64_t system) +{ + struct cpu *cpu = machine->cpus[0]; + + if (machine->machine_type == MACHINE_ARC && + (machine->machine_subtype == MACHINE_ARC_JAZZ_PICA + || machine->machine_subtype == MACHINE_ARC_JAZZ_MAGNUM)) { + uint64_t jazzbus, ali_s3, vxl; + uint64_t diskcontroller, kbdctl, ptrctl, scsi; + /* uint64_t serial1, serial2; */ + + jazzbus = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_AdapterClass, + COMPONENT_TYPE_MultiFunctionAdapter, + 0, 1, 2, 0, 0xffffffff, "Jazz-Internal Bus", + system, NULL, 0); + + /* + * DisplayController, needed by NetBSD: + * TODO: NetBSD still doesn't use it :( + */ + switch (machine->machine_subtype) { + case MACHINE_ARC_JAZZ_PICA: + /* Default TLB entries on PICA-61: */ + + /* 7: 256K, asid: 0x0, v: 0xe1000000, + p0: 0xfff00000(2.VG), p1: 0x0(0..G) */ + mips_coproc_tlb_set_entry(cpu, 7, 262144, + 0xffffffffe1000000ULL, + 0x0fff00000ULL, 0, 1, 0, 0, 0, 1, 0, 2, 0); + + /* 8: 64K, asid: 0x0, v: 0xe0000000, + p0: 0x80000000(2DVG), p1: 0x0(0..G) */ + mips_coproc_tlb_set_entry(cpu, 8, 65536, + 0xffffffffe0000000ULL, + 0x080000000ULL, 0, 1, 0, 1, 0, 1, 0, 2, 0); + + /* 9: 64K, asid: 0x0, v: 0xe00e0000, + p0: 0x800e0000(2DVG), p1: 0x800f0000(2DVG) */ + mips_coproc_tlb_set_entry(cpu, 9, 65536, + (uint64_t)0xffffffffe00e0000ULL, + (uint64_t)0x0800e0000ULL, + (uint64_t)0x0800f0000ULL, 1, 1, 1, 1, 1, 0, 2, 2); + + /* 10: 4K, asid: 0x0, v: 0xe0100000, + p0: 0xf0000000(2DVG), p1: 0x0(0..G) */ + mips_coproc_tlb_set_entry(cpu, 10, 4096, + (uint64_t)0xffffffffe0100000ULL, + (uint64_t)0x0f0000000ULL, 0,1, 0, 1, 0, 1, 0, 2, 0); + + /* 11: 1M, asid: 0x0, v: 0xe0200000, + p0: 0x60000000(2DVG), p1: 0x60100000(2DVG) */ + mips_coproc_tlb_set_entry(cpu, 11, 1048576, + 0xffffffffe0200000ULL, + 0x060000000ULL, 0x060100000ULL,1,1,1,1,1, 0, 2, 2); + + /* 12: 1M, asid: 0x0, v: 0xe0400000, + p0: 0x60200000(2DVG), p1: 0x60300000(2DVG) */ + mips_coproc_tlb_set_entry(cpu, 12, 1048576, + 0xffffffffe0400000ULL, 0x060200000ULL, + 0x060300000ULL, 1, 1, 1, 1, 1, 0, 2, 2); + + /* 13: 4M, asid: 0x0, v: 0xe0800000, + p0: 0x40000000(2DVG), p1: 0x40400000(2DVG) */ + mips_coproc_tlb_set_entry(cpu, 13, 1048576*4, + 0xffffffffe0800000ULL, 0x040000000ULL, + 0x040400000ULL, 1, 1, 1, 1, 1, 0, 2, 2); + + /* 14: 16M, asid: 0x0, v: 0xe2000000, + p0: 0x90000000(2DVG), p1: 0x91000000(2DVG) */ + mips_coproc_tlb_set_entry(cpu, 14, 1048576*16, + 0xffffffffe2000000ULL, 0x090000000ULL, + 0x091000000ULL, 1, 1, 1, 1, 1, 0, 2, 2); + + if (machine->x11_md.in_use) { + ali_s3 = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_DisplayController, + COMPONENT_FLAG_ConsoleOut | + COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "ALI_S3", + jazzbus, NULL, 0); + + arcbios_addchild_manual(cpu, + COMPONENT_CLASS_PeripheralClass, + COMPONENT_TYPE_MonitorPeripheral, + COMPONENT_FLAG_ConsoleOut | + COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "1024x768", + ali_s3, NULL, 0); + } + break; + case MACHINE_ARC_JAZZ_MAGNUM: + if (machine->x11_md.in_use) { + vxl = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_DisplayController, + COMPONENT_FLAG_ConsoleOut | + COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "VXL", + jazzbus, NULL, 0); + + arcbios_addchild_manual(cpu, + COMPONENT_CLASS_PeripheralClass, + COMPONENT_TYPE_MonitorPeripheral, + COMPONENT_FLAG_ConsoleOut | + COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "1024x768", + vxl, NULL, 0); + } + break; + } + + diskcontroller = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_DiskController, + COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "I82077", jazzbus, NULL, 0); + + /* uint64_t floppy = */ arcbios_addchild_manual(cpu, + COMPONENT_CLASS_PeripheralClass, + COMPONENT_TYPE_FloppyDiskPeripheral, + COMPONENT_FLAG_Removable | + COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, NULL, diskcontroller, NULL, 0); + + kbdctl = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_KeyboardController, + COMPONENT_FLAG_ConsoleIn | COMPONENT_FLAG_Input, + 1, 2, 0, 0xffffffff, "I8742", jazzbus, NULL, 0); + + /* uint64_t kbd = */ arcbios_addchild_manual(cpu, + COMPONENT_CLASS_PeripheralClass, + COMPONENT_TYPE_KeyboardPeripheral, + COMPONENT_FLAG_ConsoleIn | COMPONENT_FLAG_Input, + 1, 2, 0, 0xffffffff, "PCAT_ENHANCED", kbdctl, NULL, 0); + + ptrctl = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_PointerController, COMPONENT_FLAG_Input, + 1, 2, 0, 0xffffffff, "I8742", jazzbus, NULL, 0); + + /* uint64_t ptr = */ arcbios_addchild_manual(cpu, + COMPONENT_CLASS_PeripheralClass, + COMPONENT_TYPE_PointerPeripheral, COMPONENT_FLAG_Input, + 1, 2, 0, 0xffffffff, "PS2 MOUSE", ptrctl, NULL, 0); + +/* These cause Windows NT to bug out. */ +#if 0 + serial1 = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_SerialController, + COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "COM1", jazzbus, NULL, 0); + + serial2 = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_SerialController, + COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "COM1", jazzbus, NULL, 0); +#endif + + /* uint64_t paral = */ arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_ParallelController, + COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "LPT1", jazzbus, NULL, 0); + + /* uint64_t audio = */ arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ControllerClass, + COMPONENT_TYPE_AudioController, + COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, + 1, 2, 0, 0xffffffff, "MAGNUM", jazzbus, NULL, 0); + + /* uint64_t eisa = */ arcbios_addchild_manual(cpu, + COMPONENT_CLASS_AdapterClass, COMPONENT_TYPE_EISAAdapter, + 0, 1, 2, 0, 0xffffffff, "EISA", system, NULL, 0); + + { + unsigned char config[78]; + memset(config, 0, sizeof(config)); + +/* config data version: 1, revision: 2, count: 4 */ +config[0] = 0x01; config[1] = 0x00; +config[2] = 0x02; config[3] = 0x00; +config[4] = 0x04; config[5] = 0x00; config[6] = 0x00; config[7] = 0x00; + +/* + type: Interrupt + share_disposition: DeviceExclusive, flags: LevelSensitive + level: 4, vector: 22, reserved1: 0 +*/ + config[8] = arc_CmResourceTypeInterrupt; + config[9] = arc_CmResourceShareDeviceExclusive; + config[10] = arc_CmResourceInterruptLevelSensitive; + config[12] = 4; + config[16] = 22; + config[20] = 0; + +/* + type: Memory + share_disposition: DeviceExclusive, flags: ReadWrite + start: 0x 0 80002000, length: 0x1000 +*/ + config[24] = arc_CmResourceTypeMemory; + config[25] = arc_CmResourceShareDeviceExclusive; + config[26] = arc_CmResourceMemoryReadWrite; +config[28] = 0x00; config[29] = 0x20; config[30] = 0x00; config[31] = 0x80; + config[32] = 0x00; config[33] = 0x00; config[34] = 0x00; config[35] = 0x00; +config[36] = 0x00; config[37] = 0x10; config[38] = 0x00; config[39] = 0x00; + +/* + type: DMA + share_disposition: DeviceExclusive, flags: 0x0 + channel: 0, port: 0, reserved1: 0 +*/ + config[40] = arc_CmResourceTypeDMA; + config[41] = arc_CmResourceShareDeviceExclusive; +/* 42..43 = flags, 44,45,46,47 = channel, 48,49,50,51 = port, 52,53,54,55 + = reserved */ + +/* type: DeviceSpecific + share_disposition: DeviceExclusive, flags: 0x0 + datasize: 6, reserved1: 0, reserved2: 0 + data: [0x1:0x0:0x2:0x0:0x7:0x30] +*/ + config[56] = arc_CmResourceTypeDeviceSpecific; + config[57] = arc_CmResourceShareDeviceExclusive; +/* 58,59 = flags 60,61,62,63 = data size, 64..71 = reserved */ + config[60] = 6; +/* 72..77 = the data */ + config[72] = 0x01; config[73] = 0x00; config[74] = 0x02; + config[75] = 0x00; config[76] = 0x07; config[77] = 0x30; + scsi = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_AdapterClass, + COMPONENT_TYPE_SCSIAdapter, + 0, 1, 2, 0, 0xffffffff, "ESP216", + system, config, sizeof(config)); + + arcbios_register_scsicontroller(machine, scsi); + } + } +} + + +/* + * arcbios_console_init(): + * + * Called from machine.c whenever an ARC-based machine is running with + * a graphical VGA-style framebuffer, which can be used as console. + */ +void arcbios_console_init(struct machine *machine, + uint64_t vram, uint64_t ctrlregs) +{ + if (machine->md.arc == NULL) { + CHECK_ALLOCATION(machine->md.arc = (struct machine_arcbios *) + malloc(sizeof(struct machine_arcbios))); + memset(machine->md.arc, 0, sizeof(struct machine_arcbios)); + } + + machine->md.arc->vgaconsole = 1; + + machine->md.arc->console_vram = vram; + machine->md.arc->console_ctrlregs = ctrlregs; + machine->md.arc->console_maxx = ARC_CONSOLE_MAX_X; + machine->md.arc->console_maxy = ARC_CONSOLE_MAX_Y; + machine->md.arc->in_escape_sequence = 0; + machine->md.arc->escape_sequence[0] = '\0'; +} + + +struct envstrings +{ + int n; + + char **name; + char **value; +}; + +void set_env(struct envstrings* env, const char* name, const char* value) +{ + int found = -1; + + // Linear search. Slow but it works. + for (int i = 0; i < env->n; ++i) { + if (strcasecmp(env->name[i], name) == 0) { + found = i; + break; + } + } + + if (found >= 0) { + free(env->value[found]); + env->value[found] = strdup(value); + } else { + if (env->n == 0) { + env->name = malloc(0); + env->value = malloc(0); + } + + env->n ++; + + env->name = realloc(env->name, sizeof(const char*) * env->n); + env->value = realloc(env->value, sizeof(const char*) * env->n); + + env->name[env->n - 1] = strdup(name); + env->value[env->n - 1] = strdup(value); + } +} + + +static char* environment_string(struct machine *machine, struct envstrings* env, const char* variable_name, bool name_and_value) +{ + size_t len = strlen(variable_name); + int found = -1; + + // Linear search. Slow but it works. + for (int i = 0; i < env->n; ++i) { + if (strcasecmp(env->name[i], variable_name) == 0) { + found = i; + break; + } + } + + size_t len_with_value = len + 1; + if (found >= 0) + len_with_value += strlen(env->value[found]); + + char* s = malloc(len_with_value + 1); + + if (name_and_value) { + if (found < 0) + snprintf(s, len_with_value + 1, "%s=", variable_name); + else + snprintf(s, len_with_value + 1, "%s=%s", variable_name, env->value[found]); + } else { + // Value only. + if (found < 0) + s[0] = '\0'; + else + snprintf(s, len_with_value + 1, "%s", env->value[found]); + } + + if (machine->machine_type == MACHINE_ARC) { + for (size_t i = 0; i < len; ++i) + s[i] = toupper(s[i]); + } + + return s; +} + + +/* + * arc_environment_setup(): + * + * Initialize the emulated environment variables. + */ +static void arc_environment_setup(struct machine *machine, int is64bit, + const char *primary_ether_addr) +{ + struct envstrings* env = malloc(sizeof(struct envstrings)); + memset(env, 0, sizeof(struct envstrings)); + + uint64_t addr, addr2; + struct cpu *cpu = machine->cpus[0]; + + /* + * Boot string in ARC format: + * + * TODO: How about floppies? multi()disk()fdisk() + * Is tftp() good for netbooting? + */ + char *boot_device; + + if (machine->bootdev_id < 0 || machine->force_netboot) { + boot_device = "tftp()"; + } else { + char* prefix = ""; + + if (machine->machine_type == MACHINE_SGI) { + switch (machine->machine_subtype) { + case 30: + prefix = "xio(0)pci(15)"; + break; + case 32: + prefix = "pci(0)"; + break; + default: + fprintf(stderr, "TODO: prefix for SGI IP%i\n", machine->machine_subtype); + exit(1); + } + } + + boot_device = prefix; + + if (diskimage_is_a_cdrom(machine, machine->bootdev_id, machine->bootdev_type)) { + size_t len = strlen(boot_device) + 50; + char* cdrom = malloc(len); + snprintf(cdrom, len, "%sscsi(0)cdrom(%i)", boot_device, machine->bootdev_id); + boot_device = cdrom; + } else { + size_t len = strlen(boot_device) + 50; + char* disk = malloc(len); + snprintf(disk, len, "%sscsi(0)disk(%i)rdisk(0)", boot_device, machine->bootdev_id); + boot_device = disk; + } + + char *systempartition; + if (machine->machine_type == MACHINE_SGI || !diskimage_is_a_cdrom(machine, machine->bootdev_id, machine->bootdev_type)) { + int partition = 1; // default ARC partition? + if (machine->machine_type == MACHINE_SGI) + partition = 8; + + size_t len = strlen(boot_device) + 50; + systempartition = malloc(len); + snprintf(systempartition, len, "%spartition(%i)", boot_device, partition); + } else { + size_t len = strlen(boot_device) + 50; + systempartition = malloc(len); + snprintf(systempartition, len, "%sfdisk(0)", boot_device); + } + + set_env(env, "SystemPartition", systempartition); + + char *osloadpartition; + if (machine->machine_type == MACHINE_SGI || !diskimage_is_a_cdrom(machine, machine->bootdev_id, machine->bootdev_type)) { + int partition = 1; // default ARC partition? + if (machine->machine_type == MACHINE_SGI) + partition = 0; + + size_t len = strlen(boot_device) + 50; + osloadpartition = malloc(len); + snprintf(osloadpartition, len, "%spartition(%i)", boot_device, partition); + } else { + size_t len = strlen(boot_device) + 50; + osloadpartition = malloc(len); + snprintf(osloadpartition, len, "%sfdisk(0)", boot_device); + } + + set_env(env, "OSLoadPartition", osloadpartition); + } + + if (machine->machine_type == MACHINE_ARC) { + set_env(env, "OSLoader", "\\os\\nt\\osloader.exe"); + set_env(env, "OSLoadFilename", "\\todo"); + } else { + set_env(env, "OSLoader", "sash"); + set_env(env, "OSLoadFilename", "/unix"); + } + + if (machine->boot_kernel_filename[0] != '\0') { + size_t len = strlen(machine->boot_kernel_filename) + 10; + char* s = malloc(len); + snprintf(s, len, "/%s", machine->boot_kernel_filename); + set_env(env, "OSLoadFilename", s); + } + + if (machine->machine_type == MACHINE_SGI) { + /* g for graphical mode. G for graphical mode with SGI logo visible on Irix? */ + if (machine->x11_md.in_use) { + set_env(env, "ConsoleIn", "keyboard()"); + set_env(env, "ConsoleOut", "video()"); + set_env(env, "console", "g"); + set_env(env, "gfx", "alive"); + } else { + /* 'd' or 'd2' in Irix, 'ttyS0' in Linux? */ + set_env(env, "ConsoleIn", "serial(0)"); + set_env(env, "ConsoleOut", "serial(0)"); + set_env(env, "console", "d"); + set_env(env, "gfx", "dead"); + } + + set_env(env, "AutoLoad", "No"); + + if (machine->bootdev_id < 0 || machine->force_netboot) { + /* + * diskless=1 means boot from network disk? (nfs?) + * diskless=2 means boot from network tape? TODO + */ + set_env(env, "diskless", "1"); + + // store_pointer_and_advance(cpu, &addr2, addr, is64bit); + // add_environment_string(cpu, "tapedevice=bootp()10.0.0.2:/dev/tape", &addr); + + set_env(env, "root", "xyz"); // TODO + + set_env(env, "bootfile", "bootp()10.0.0.2:/var/boot/client/unix"); + set_env(env, "SystemPartition", "bootp()10.0.0.2:/var/boot/client"); + set_env(env, "OSLoadPartition", "bootp()10.0.0.2:/var/boot/client"); + } else { + set_env(env, "diskless", "0"); + } + + /* TODO: Keep these variables in sync with bootblock loading, + i.e. OSLoader is the name of the voldir entry to boot + with. */ + + set_env(env, "kernname", "unix"); // TODO: like OSLoadFilename? + + set_env(env, "volume", "80"); + set_env(env, "sgilogo", "y"); + set_env(env, "monitor", "h"); + set_env(env, "TimeZone", "GMT"); + set_env(env, "nogfxkbd", "1"); + set_env(env, "keybd", "US"); + set_env(env, "cpufreq", "123"); + set_env(env, "dbaud", "9600"); + set_env(env, "rbaud", "9600"); + set_env(env, "rebound", "y"); + set_env(env, "crt_option", "1"); + set_env(env, "netaddr", "10.0.0.1"); + set_env(env, "netmask", "255.0.0.0"); + set_env(env, "dlserver", "10.0.0.2"); + set_env(env, "srvaddr", "10.0.0.2"); + set_env(env, "eaddr", primary_ether_addr); + + // showconfig 0 means don't show. 1 means show some. + // 2 means show more. TODO: higher values? + set_env(env, "showconfig", "255"); + + set_env(env, "verbose", "1"); + set_env(env, "diagmode", "v"); + set_env(env, "debug_bigmem", "1"); + } else { + // General ARC: + if (machine->x11_md.in_use) { + set_env(env, "ConsoleIn", "multi()key()keyboard()console()"); + set_env(env, "ConsoleOut", "multi()video()monitor()console()"); + } else { + /* TODO: serial console for ARC? */ + set_env(env, "ConsoleIn", "multi()serial(0)"); + set_env(env, "ConsoleOut", "multi()serial(0)"); + } + } + + /* Boot string is either: + SystemPartition + OSLoader (e.g. sash) + or + OSLoadPartition + OSLoadFilename (e.g. /unix) */ + + char* s1 = environment_string(machine, env, "SystemPartition", true); + char* s2 = environment_string(machine, env, "OSLoader", true); + size_t s3len = strlen(s1) + strlen(s2) + 100; + char* boot_string = malloc(s3len); + snprintf(boot_string, s3len, "%s%s%s", s1, machine->machine_type == MACHINE_SGI ? "/" : "\\", s2); + free(s2); + free(s1); + + // boot_string = env["OSLoadPartition"] + env["OSLoadFilename"]; + + /* Boot args., eg "-a" */ + machine->bootarg = machine->boot_string_argument; + + if (machine->machine_type == MACHINE_SGI) { + set_env(env, "OSLoadOptions", "auto"); + } else { + set_env(env, "OSLoadOptions", machine->bootarg); + } + + /* a0 = argc: */ + cpu->cd.mips.gpr[MIPS_GPR_A0] = 0; /* note: argc is increased later */ + + /* sp = just below top of RAM. (TODO: not needed?) */ + cpu->cd.mips.gpr[MIPS_GPR_SP] = (int64_t)(int32_t) + (machine->physical_ram_in_mb * 1048576 + 0x80000000 - 0x2080); + + /* a1 = argv: */ + addr = ARC_ENV_STRINGS; + addr2 = ARC_ARGV_START; + cpu->cd.mips.gpr[MIPS_GPR_A1] = addr2; + + CHECK_ALLOCATION(machine->bootstr = strdup(boot_string)); + + /* bootstr: */ + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + add_environment_string(cpu, machine->bootstr, &addr); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + /* bootarg: */ + if (machine->bootarg[0] != '\0') { + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + add_environment_string(cpu, machine->bootarg, &addr); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + } + + /* A few of the environment variables are also included as regular + arguments, as per + https://misc.openbsd.narkive.com/6hkw57ju/openbsd-sgi-snapshot-fails-to-boot-from-harddisk#post2 */ + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + char* ev = environment_string(machine, env, "OSLoadOptions", true); + add_environment_string(cpu, ev, &addr); + free(ev); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + ev = environment_string(machine, env, "ConsoleIn", true); + add_environment_string(cpu, ev, &addr); + free(ev); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + ev = environment_string(machine, env, "ConsoleOut", true); + add_environment_string(cpu, ev, &addr); + free(ev); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + ev = environment_string(machine, env, "SystemPartition", true); + add_environment_string(cpu, ev, &addr); + free(ev); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + ev = environment_string(machine, env, "OSLoader", true); + add_environment_string(cpu, ev, &addr); + free(ev); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + ev = environment_string(machine, env, "OSLoadPartition", true); + add_environment_string(cpu, ev, &addr); + free(ev); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + ev = environment_string(machine, env, "OSLoadFilename", true); + add_environment_string(cpu, ev, &addr); + free(ev); + cpu->cd.mips.gpr[MIPS_GPR_A0] ++; + + /* a2 = envp: */ + cpu->cd.mips.gpr[MIPS_GPR_A2] = addr2; + + if (machine->machine_type == MACHINE_SGI) { + /* + * The SGI O2 PROM contains an "env" section header like this: + * + * 00004000 00 00 00 00 00 00 00 00 53 48 44 52 00 00 04 00 |........SHDR....| + * 00004010 03 03 00 00 65 6e 76 00 00 00 00 00 00 00 00 00 |....env.........| + * 00004020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + * 00004030 00 00 00 00 31 2e 30 00 00 00 00 00 13 18 11 ae |....1.0.........| + * + * followed by environment variables at 0x4040. It is not required + * by NetBSD/OpenBSD/Linux, but Irix seems to hardcodedly look into + * the PROM address space for this header. + */ + store_32bit_word(cpu, ARC_ENV_SGI + 0x08, 0x53484452); + store_32bit_word(cpu, ARC_ENV_SGI + 0x0c, 0x00000400); + store_32bit_word(cpu, ARC_ENV_SGI + 0x10, 0x03030000); + store_32bit_word(cpu, ARC_ENV_SGI + 0x14, 0x656e7600); + store_32bit_word(cpu, ARC_ENV_SGI + 0x34, 0x312e3000); + store_32bit_word(cpu, ARC_ENV_SGI + 0x3c, 0x131811ae); + addr = ARC_ENV_STRINGS_SGI; + } + + /* + * Add environment variables. For each variable, add it as a string + * using add_environment_string(), and add a pointer to it to the + * pointer array. + */ + for (int i = 0; i < env->n; ++i) { + store_pointer_and_advance(cpu, &addr2, addr, is64bit); + char* s = environment_string(machine, env, env->name[i], true); + add_environment_string(cpu, s, &addr); + free(s); + } + + /* End the environment strings with an empty zero-terminated + string, and the envp array with a NULL pointer. */ + add_environment_string(cpu, "", &addr); /* the end */ + store_pointer_and_advance(cpu, &addr2, 0, is64bit); + + /* Return address: (0x20 = ReturnFromMain()) */ + cpu->cd.mips.gpr[MIPS_GPR_RA] = ARC_FIRMWARE_ENTRIES + 0x20; +} + + +/* + * arcbios_init(): + * + * Should be called before any other arcbios function is used. An exception + * is arcbios_console_init(), which may be called before this function. + * + * TODO: Refactor; this is too long. + */ +void arcbios_init(struct machine *machine, int is64bit, uint64_t sgi_ram_offset, + const char *primary_ether_addr, uint8_t *primary_ether_macaddr) +{ + int i, alloclen = 20; + char *name; + uint64_t arc_reserved, mem_base; + struct cpu *cpu = machine->cpus[0]; + struct arcbios_dsp_stat arcbios_dsp_stat; + uint64_t system = 0; + + if (machine->md.arc == NULL) { + CHECK_ALLOCATION(machine->md.arc = (struct machine_arcbios *) + malloc(sizeof(struct machine_arcbios))); + memset(machine->md.arc, 0, sizeof(struct machine_arcbios)); + } + + machine->md.arc->arc_64bit = is64bit; + machine->md.arc->wordlen = is64bit? sizeof(uint64_t) : sizeof(uint32_t); + + machine->md.arc->next_component_address = FIRST_ARC_COMPONENT; + machine->md.arc->configuration_data_next_addr = ARC_CONFIG_DATA_ADDR; + + if (machine->physical_ram_in_mb < 16) + fprintf(stderr, "WARNING! The ARC platform specification " + "doesn't allow less than 16 MB of RAM. Continuing " + "anyway.\n"); + + /* File handles 0, 1, and 2 are stdin, stdout, and stderr. */ + for (i=0; imd.arc->file_handle_in_use[i] = i<3? 1 : 0; + machine->md.arc->file_handle_string[i] = i>=3? NULL : + (i==0? "(stdin)" : (i==1? "(stdout)" : "(stderr)")); + machine->md.arc->current_seek_offset[i] = 0; + } + + if (!machine->x11_md.in_use) + machine->md.arc->vgaconsole = 0; + + if (machine->md.arc->vgaconsole) { + char tmpstr[100]; + int x, y; + + machine->md.arc->console_curcolor = 0x1f; + for (y=0; ymd.arc->console_maxy; y++) + for (x=0; xmd.arc->console_maxx; x++) + arcbios_putcell(cpu, ' ', x, y); + + machine->md.arc->console_curx = 0; + machine->md.arc->console_cury = 0; + + arcbios_putstring(cpu, "GXemul " VERSION" ARCBIOS emulation\n"); + + snprintf(tmpstr, sizeof(tmpstr), "%i cpu%s (%s), %i MB " + "memory\n\n", machine->ncpus, machine->ncpus > 1? "s" : "", + cpu->cd.mips.cpu_type.name, + machine->physical_ram_in_mb); + arcbios_putstring(cpu, tmpstr); + } + + arcbios_set_default_exception_handler(cpu); + + struct arcbios_sysid arcbios_sysid; + memset(&arcbios_sysid, 0, sizeof(arcbios_sysid)); + if (machine->machine_type == MACHINE_SGI) { + /* Vendor ID, max 8 chars: */ + memcpy(arcbios_sysid.VendorId, "SGI", 3); + + switch (machine->machine_subtype) { + case 22: + memcpy(arcbios_sysid.ProductId, "87654321", 8); /* some kind of ID? */ + break; + case 32: + memcpy(arcbios_sysid.ProductId, "f", 1); /* "6", "8", of "f"? It's "f" on my O2. */ + break; + default: + snprintf(arcbios_sysid.ProductId, 8, "IP%i", machine->machine_subtype); + } + } else { + switch (machine->machine_subtype) { + case MACHINE_ARC_JAZZ_PICA: + memcpy(arcbios_sysid.VendorId, "MIPS MAG", 8); + memcpy(arcbios_sysid.ProductId, "ijkl", 4); + break; + case MACHINE_ARC_JAZZ_MAGNUM: + memcpy(arcbios_sysid.VendorId, "MIPS MAG", 8); + memcpy(arcbios_sysid.ProductId, "ijkl", 4); + break; + default: + fatal("error in machine.c sysid\n"); + exit(1); + } + } + + store_buf(cpu, SGI_SYSID_ADDR, (char *)&arcbios_sysid, sizeof(arcbios_sysid)); + + arcbios_get_dsp_stat(cpu, &arcbios_dsp_stat); + store_buf(cpu, ARC_DSPSTAT_ADDR, (char *)&arcbios_dsp_stat, sizeof(arcbios_dsp_stat)); + + /* + * The first 12 MBs of RAM are simply reserved... this simplifies + * things a lot. If there's more than 512MB of RAM, it has to be + * split in two, according to the ARC spec. + * + * However, the region of physical address space between 0x10000000 + * and 0x1fffffff (256 - 512 MB) is sometimes occupied by memory + * mapped devices, for example in the SGI O2, so that portion can not + * be used. + * + * Instead, any high memory needs to be added using a machine-specific + * high address. + */ + int reserved_bottom_mem_in_mb = 12; + int free_type = ARCBIOS_MEM_FreeMemory; + + machine->md.arc->memdescriptor_base = ARC_MEMDESC_ADDR; + + arc_reserved = 0x2000; + if (machine->machine_type == MACHINE_SGI) + arc_reserved = 0x4000; + + arcbios_add_memory_descriptor(cpu, 0, arc_reserved, + ARCBIOS_MEM_FirmwarePermanent); + arcbios_add_memory_descriptor(cpu, sgi_ram_offset + arc_reserved, + 0x60000-arc_reserved, ARCBIOS_MEM_FirmwareTemporary); + + uint64_t ram = 0; + + // Default is to use a physical memory base around zero (0). + mem_base = sgi_ram_offset / 1048576; + + while (ram < machine->physical_ram_in_mb) { + uint64_t to_add = machine->physical_ram_in_mb - ram; + + if (to_add > 256) + to_add = 256; + + if (ram == 0) { + // Skip first few MB of RAM, for reserved structures. + ram += reserved_bottom_mem_in_mb; + mem_base += reserved_bottom_mem_in_mb; + to_add -= reserved_bottom_mem_in_mb; + } + + arcbios_add_memory_descriptor(cpu, mem_base * 1048576, + to_add * 1048576, free_type); + + ram += to_add; + mem_base += to_add; + + if (mem_base == 256) { + if (machine->machine_type == MACHINE_SGI && + machine->machine_subtype == 32) { + // mem_base = 0x50000000 / 1048576; + // Actually, the above does not seem to work. + // Perhaps the ARCS in the O2 simply says + // 256 MB regardless of how much more there + // is in the machine? + break; + } else { + fatal("Ignoring RAM above 256 MB! (Not yet " + "implemented for this machine type.)\n"); + break; + } + } + } + + /* + * Components: (this is an example of what a system could look like) + * + * [System] + * [CPU] (one for each cpu) + * [FPU] (one for each cpu) + * [CPU Caches] + * [Memory] + * [Ethernet] + * [Serial] + * [SCSI] + * [Disk] + * + * Here's a good list of what hardware is in different IP-models: + * http://www.linux-mips.org/archives/linux-mips/2001-03/msg00101.html + */ + + if (machine->machine_name == NULL) + fatal("ERROR: machine_name == NULL\n"); + + /* Add the root node: */ + switch (machine->machine_type) { + + case MACHINE_SGI: + debug("ARCS:\n"); + debug_indentation(1); + + CHECK_ALLOCATION(name = (char *) malloc(alloclen)); + snprintf(name, alloclen, "SGI-IP%i", machine->machine_subtype); + + /* A very special case for IP24 (which identifies itself + as an IP22): */ + if (machine->machine_subtype == 24) + snprintf(name, alloclen, "SGI-IP22"); + break; + + case MACHINE_ARC: + debug("ARC:\n"); + debug_indentation(1); + + switch (machine->machine_subtype) { + case MACHINE_ARC_JAZZ_PICA: + name = strdup("PICA-61"); + break; + case MACHINE_ARC_JAZZ_MAGNUM: + name = strdup("Microsoft-Jazz"); + break; + default: + fatal("Unimplemented ARC machine type %i\n", + machine->machine_subtype); + exit(1); + } + break; + + default: + fatal("ERROR: non-SGI and non-ARC?\n"); + exit(1); + } + + system = arcbios_addchild_manual(cpu, COMPONENT_CLASS_SystemClass, + COMPONENT_TYPE_ARC, 0,1,2,0, 0xffffffff, name, 0/*ROOT*/, NULL, 0); + debug("system @ 0x%" PRIx64" (\"%s\")\n", (uint64_t) system, name); + + + /* + * Add tree nodes for CPUs and their caches: + */ + + for (i=0; incpus; i++) { + uint64_t cpuaddr, fpu=0, picache, pdcache, sdcache=0; + int cache_size, cache_line_size; + unsigned int jj; + char arc_cpu_name[100]; + char arc_fpc_name[105]; + + snprintf(arc_cpu_name, sizeof(arc_cpu_name), + "MIPS-%s", machine->cpu_name); + + arc_cpu_name[sizeof(arc_cpu_name)-1] = 0; + for (jj=0; jj= 'a' && arc_cpu_name[jj] <= 'z') + arc_cpu_name[jj] += ('A' - 'a'); + + strlcpy(arc_fpc_name, arc_cpu_name, sizeof(arc_fpc_name)); + strlcat(arc_fpc_name, "FPC", sizeof(arc_fpc_name)); + + cpuaddr = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ProcessorClass, COMPONENT_TYPE_CPU, + 0, 1, 2, i, 0xffffffff, arc_cpu_name, system, NULL, 0); + + /* + * TODO: This was in the ARC specs, but it isn't really used + * by ARC implementations? At least SGI-IP32 uses it. + */ + if (machine->machine_type == MACHINE_SGI) + fpu = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_ProcessorClass, COMPONENT_TYPE_FPU, + 0, 1, 2, 0, 0xffffffff, arc_fpc_name, cpuaddr, + NULL, 0); + + cache_size = DEFAULT_PCACHE_SIZE - 12; + if (cpu->cd.mips.cache_picache) + cache_size = cpu->cd.mips.cache_picache - 12; + if (cache_size < 0) + cache_size = 0; + + cache_line_size = DEFAULT_PCACHE_LINESIZE; + if (cpu->cd.mips.cache_picache_linesize) + cache_line_size = cpu->cd.mips.cache_picache_linesize; + if (cache_line_size < 0) + cache_line_size = 0; + + picache = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_CacheClass, COMPONENT_TYPE_PrimaryICache, + 0, 1, 2, + /* + * Key bits: 0xXXYYZZZZ + * XX is refill-size. + * Cache line size is 1 << YY, + * Cache size is 4KB << ZZZZ. + */ + 0x01000000 + (cache_line_size << 16) + cache_size, + /* 32 bytes per line, default = 32 KB total */ + 0xffffffff, NULL, cpuaddr, NULL, 0); + + cache_size = DEFAULT_PCACHE_SIZE - 12; + if (cpu->cd.mips.cache_pdcache) + cache_size = cpu->cd.mips.cache_pdcache - 12; + if (cache_size < 0) + cache_size = 0; + + cache_line_size = DEFAULT_PCACHE_LINESIZE; + if (cpu->cd.mips.cache_pdcache_linesize) + cache_line_size = cpu->cd.mips.cache_pdcache_linesize; + if (cache_line_size < 0) + cache_line_size = 0; + + pdcache = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_CacheClass, + COMPONENT_TYPE_PrimaryDCache, 0, 1, 2, + /* + * Key bits: 0xYYZZZZ + * Cache line size is 1 << YY, + * Cache size is 4KB << ZZZZ. + */ + 0x01000000 + (cache_line_size << 16) + cache_size, + /* 32 bytes per line, default = 32 KB total */ + 0xffffffff, NULL, cpuaddr, NULL, 0); + + if (cpu->cd.mips.cache_secondary >= 12) { + cache_size = cpu->cd.mips.cache_secondary - 12; + + cache_line_size = 6; /* 64 bytes default */ + if (cpu->cd.mips.cache_secondary_linesize) + cache_line_size = cpu->cd.mips. + cache_secondary_linesize; + if (cache_line_size < 0) + cache_line_size = 0; + + sdcache = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_CacheClass, + COMPONENT_TYPE_SecondaryDCache, 0, 1, 2, + /* + * Key bits: 0xYYZZZZ + * Cache line size is 1 << YY, + * Cache size is 4KB << ZZZZ. + */ + 0x01000000 + (cache_line_size << 16) + cache_size, + /* 64 bytes per line, default = 1 MB total */ + 0xffffffff, NULL, cpuaddr, NULL, 0); + } + + debug("cpu%i @ 0x%" PRIx64, i, (uint64_t) cpuaddr); + + if (fpu != 0) + debug(" (fpu @ 0x%" PRIx64")\n", (uint64_t) fpu); + else + debug("\n"); + + debug(" picache @ 0x%" PRIx64", pdcache @ 0x%" PRIx64"\n", + (uint64_t) picache, (uint64_t) pdcache); + + if (cpu->cd.mips.cache_secondary >= 12) + debug(" sdcache @ 0x%" PRIx64"\n", + (uint64_t) sdcache); + + if (machine->machine_type == MACHINE_SGI) { + /* TODO: Memory amount (and base address?)! */ + uint64_t memory = arcbios_addchild_manual(cpu, + COMPONENT_CLASS_MemoryClass, + COMPONENT_TYPE_MemoryUnit, 0, 1, 2, 0, + 0xffffffff, "memory", cpuaddr, NULL, 0); + debug("memory @ 0x%" PRIx64"\n", (uint64_t) memory); + } + } + + + /* + * Add other components: + * + * TODO: How should this be synched with the hardware devices + * added in machine.c? + */ + + arcbios_add_other_components(machine, system); + + + /* + * Defalt TLB entry for 64-bit SGI machines: + */ + if (machine->machine_type == MACHINE_SGI) { + switch (machine->machine_subtype) { + case 12: + /* TODO: Not on 12? */ + break; + case 32: + /* Not needed for SGI O2? */ + break; + default: + mips_coproc_tlb_set_entry(cpu, 0, 1048576*16, + 0xc000000000000000ULL, 0, 1048576*16, 1,1,1,1,1, 0, 2, 2); + } + } + + + /* + * Set up Firmware Vectors: + */ + add_symbol_name(&machine->symbol_context, ARC_FIRMWARE_ENTRIES, 0x10000, "[ARCBIOS entry]", 0, 1); + + for (i=0; i<100; i++) { + if (is64bit) { + store_64bit_word(cpu, ARC_FIRMWARE_VECTORS + i*8, ARC_FIRMWARE_ENTRIES + i*8); + store_64bit_word(cpu, ARC_PRIVATE_VECTORS + i*8, ARC_PRIVATE_ENTRIES + i*8); + + /* "Magic trap" instruction: */ + store_32bit_word(cpu, ARC_FIRMWARE_ENTRIES + i*8, 0x00c0de0c); + store_32bit_word(cpu, ARC_PRIVATE_ENTRIES + i*8, 0x00c0de0c); + } else { + store_32bit_word(cpu, ARC_FIRMWARE_VECTORS + i*4, ARC_FIRMWARE_ENTRIES + i*4); + store_32bit_word(cpu, ARC_PRIVATE_VECTORS + i*4, ARC_PRIVATE_ENTRIES + i*4); + + /* "Magic trap" instruction: */ + store_32bit_word(cpu, ARC_FIRMWARE_ENTRIES + i*4, 0x00c0de0c); + store_32bit_word(cpu, ARC_PRIVATE_ENTRIES + i*4, 0x00c0de0c); + } + } + + + /* + * Set up the ARC SPD: + */ + if (is64bit) { + /* ARCS64 SPD (TODO: This is just a guess) */ + struct arcbios_spb_64 arcbios_spb_64; + memset(&arcbios_spb_64, 0, sizeof(arcbios_spb_64)); + store_64bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.SPBSignature, ARCBIOS_SPB_SIGNATURE); + store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.Version, 64); + store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.Revision, 0); + store_64bit_word_in_host(cpu, (unsigned char *) &arcbios_spb_64.FirmwareVector, ARC_FIRMWARE_VECTORS); + store_buf(cpu, SGI_SPB_ADDR, (char *)&arcbios_spb_64, sizeof(arcbios_spb_64)); + } else { + /* ARCBIOS SPB: (For ARC and 32-bit SGI modes) */ + struct arcbios_spb arcbios_spb; + memset(&arcbios_spb, 0, sizeof(arcbios_spb)); + store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.SPBSignature, ARCBIOS_SPB_SIGNATURE); + store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.SPBLength, sizeof(arcbios_spb)); + store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.Version, 1); + store_16bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.Revision, machine->machine_type == MACHINE_SGI? 10 : 2); + store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.FirmwareVector, ARC_FIRMWARE_VECTORS); + store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.FirmwareVectorLength, 35 * sizeof(uint32_t)); + store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.PrivateVector, ARC_PRIVATE_VECTORS); + store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.PrivateVectorLength, 13 * sizeof(uint32_t)); + + if (machine->machine_type == MACHINE_SGI) { + // Mimic the "BTSR" Restart block struct on my real O2: + // "sash" clears the lowest bit of the word at offset 0x1c, which + // is the "Boot Status" word according to the ARC spec. + // The lowest bit means "boot started". + const uint64_t btsr_addr = SGI_SPB_ADDR + 0x80; + store_32bit_word_in_host(cpu, (unsigned char *) &arcbios_spb.RestartBlock, btsr_addr); + + store_32bit_word(cpu, btsr_addr + 0x00, 0x42545352); + store_32bit_word(cpu, btsr_addr + 0x1c, 0x40); // 0x40 means "Processor Ready" + } + + store_buf(cpu, SGI_SPB_ADDR, (char *)&arcbios_spb, sizeof(arcbios_spb)); + } + + + /* + * TODO: How to build the component tree intermixed with + * the rest of device initialization? + */ + + arc_environment_setup(machine, is64bit, primary_ether_addr); + + debug_indentation(-1); +} + diff -Nru gxemul-0.6.2/src/promemul/arcbios.cc gxemul-0.7.0+dfsg/src/promemul/arcbios.cc --- gxemul-0.6.2/src/promemul/arcbios.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/arcbios.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,2952 +0,0 @@ -/* - * Copyright (C) 2003-2019 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: ARCBIOS and ARCS emulation - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "arcbios.h" -#include "console.h" -#include "cpu.h" -#include "cpu_mips.h" -#include "diskimage.h" -#include "machine.h" -#include "machine_arc.h" -#include "memory.h" -#include "misc.h" - -#include "thirdparty/arcbios_other.h" - - -extern int quiet_mode; -extern int verbose; - - -/* - * arcbios_add_string_to_component(): - */ -void arcbios_add_string_to_component(struct machine *machine, - char *str, uint64_t component) -{ - if (machine->md.arc->n_string_to_components - >= MAX_STRING_TO_COMPONENT) { - printf("Too many string-to-component mappings.\n"); - exit(1); - } - - CHECK_ALLOCATION(machine->md.arc->string_to_component[machine-> - md.arc->n_string_to_components] = strdup(str)); - - debug("adding ARC component mapping: 0x%08x = %s\n", - (int)component, str); - - machine->md.arc->string_to_component_value[ - machine->md.arc->n_string_to_components] = component; - - machine->md.arc->n_string_to_components ++; -} - - -/* - * arcbios_get_dsp_stat(): - * - * Fills in an arcbios_dsp_stat struct with valid data. - */ -static void arcbios_get_dsp_stat(struct cpu *cpu, - struct arcbios_dsp_stat *dspstat) -{ - memset(dspstat, 0, sizeof(struct arcbios_dsp_stat)); - - store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> - CursorXPosition, cpu->machine->md.arc->console_curx + 1); - store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> - CursorYPosition, cpu->machine->md.arc->console_cury + 1); - store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> - CursorMaxXPosition, ARC_CONSOLE_MAX_X); - store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> - CursorMaxYPosition, ARC_CONSOLE_MAX_Y); - dspstat->ForegroundColor = cpu->machine->md.arc->console_curcolor; - dspstat->HighIntensity = cpu->machine->md.arc->console_curcolor ^ 0x08; -} - - -/* - * arcbios_putcell(): - */ -static void arcbios_putcell(struct cpu *cpu, int ch, int x, int y) -{ - unsigned char buf[2]; - buf[0] = ch; - buf[1] = cpu->machine->md.arc->console_curcolor; - if (cpu->machine->md.arc->console_reverse) - buf[1] = ((buf[1] & 0x70) >> 4) | ((buf[1] & 7) << 4) - | (buf[1] & 0x88); - cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc->console_vram + - 2*(x + cpu->machine->md.arc->console_maxx * y), - &buf[0], sizeof(buf), MEM_WRITE, - CACHE_NONE | PHYSICAL); -} - - -/* - * handle_esc_seq(): - * - * Used by arcbios_putchar(). - */ -static void handle_esc_seq(struct cpu *cpu) -{ - int i, len = strlen(cpu->machine->md.arc->escape_sequence); - int row, col, color, code, start, stop; - char *p; - - if (cpu->machine->md.arc->escape_sequence[0] != '[') - return; - - code = cpu->machine->md.arc->escape_sequence[len-1]; - cpu->machine->md.arc->escape_sequence[len-1] = '\0'; - - switch (code) { - case 'm': - color = atoi(cpu->machine->md.arc->escape_sequence + 1); - switch (color) { - case 0: /* Default. */ - cpu->machine->md.arc->console_curcolor = 0x1f; - cpu->machine->md.arc->console_reverse = 0; break; - case 1: /* "Bold". */ - cpu->machine->md.arc->console_curcolor |= 0x08; break; - case 7: /* "Reverse". */ - cpu->machine->md.arc->console_reverse = 1; break; - case 30: /* Black foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x00; break; - case 31: /* Red foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x04; break; - case 32: /* Green foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x02; break; - case 33: /* Yellow foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x06; break; - case 34: /* Blue foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x01; break; - case 35: /* Red-blue foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x05; break; - case 36: /* Green-blue foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x03; break; - case 37: /* White foreground. */ - cpu->machine->md.arc->console_curcolor &= 0xf0; - cpu->machine->md.arc->console_curcolor |= 0x07; break; - case 40: /* Black background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x00; break; - case 41: /* Red background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x40; break; - case 42: /* Green background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x20; break; - case 43: /* Yellow background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x60; break; - case 44: /* Blue background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x10; break; - case 45: /* Red-blue background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x50; break; - case 46: /* Green-blue background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x30; break; - case 47: /* White background. */ - cpu->machine->md.arc->console_curcolor &= 0x0f; - cpu->machine->md.arc->console_curcolor |= 0x70; break; - default:fatal("{ handle_esc_seq: color %i }\n", color); - } - return; - case 'H': - p = strchr(cpu->machine->md.arc->escape_sequence, ';'); - if (p == NULL) - return; /* TODO */ - row = atoi(cpu->machine->md.arc->escape_sequence + 1); - col = atoi(p + 1); - if (col < 1) - col = 1; - if (row < 1) - row = 1; - cpu->machine->md.arc->console_curx = col - 1; - cpu->machine->md.arc->console_cury = row - 1; - return; - case 'J': - /* - * J = clear screen below cursor, and the rest of the - * current line, - * 2J = clear whole screen. - */ - i = atoi(cpu->machine->md.arc->escape_sequence + 1); - if (i != 0 && i != 2) - fatal("{ handle_esc_seq(): %iJ }\n", i); - if (i == 0) - for (col = cpu->machine->md.arc->console_curx; - col < cpu->machine->md.arc->console_maxx; col++) - arcbios_putcell(cpu, ' ', col, - cpu->machine->md.arc->console_cury); - for (col = 0; col < cpu->machine->md.arc->console_maxx; col++) - for (row = i? 0 : cpu->machine->md.arc->console_cury+1; - row < cpu->machine->md.arc->console_maxy; row++) - arcbios_putcell(cpu, ' ', col, row); - return; - case 'K': - col = atoi(cpu->machine->md.arc->escape_sequence + 1); - /* 2 = clear line to the right. 1 = to the left (?) */ - start = 0; stop = cpu->machine->md.arc->console_curx; - if (col == 2) { - start = cpu->machine->md.arc->console_curx; - stop = cpu->machine->md.arc->console_maxx - 1; - } - for (i=start; i<=stop; i++) - arcbios_putcell(cpu, ' ', i, - cpu->machine->md.arc->console_cury); - - return; - } - - fatal("{ handle_esc_seq(): unimplemented escape sequence: "); - for (i=0; imachine->md.arc->escape_sequence[i]; - if (i == len-1) - x = code; - - if (x >= ' ' && x < 127) - fatal("%c", x); - else - fatal("[0x%02x]", x); - } - fatal(" }\n"); -} - - -/* - * scroll_if_necessary(): - */ -static void scroll_if_necessary(struct cpu *cpu) -{ - /* Scroll? */ - if (cpu->machine->md.arc->console_cury >= - cpu->machine->md.arc->console_maxy) { - unsigned char buf[2]; - int x, y; - for (y=0; ymachine->md.arc->console_maxy-1; y++) - for (x=0; xmachine->md.arc->console_maxx; - x++) { - cpu->memory_rw(cpu, cpu->mem, - cpu->machine->md.arc->console_vram + - 2*(x + cpu->machine->md.arc-> - console_maxx * (y+1)), - &buf[0], sizeof(buf), MEM_READ, - CACHE_NONE | PHYSICAL); - cpu->memory_rw(cpu, cpu->mem, - cpu->machine->md.arc->console_vram + - 2*(x + cpu->machine->md.arc-> - console_maxx * y), - &buf[0], sizeof(buf), MEM_WRITE, - CACHE_NONE | PHYSICAL); - } - - cpu->machine->md.arc->console_cury = - cpu->machine->md.arc->console_maxy - 1; - - for (x=0; xmachine->md.arc->console_maxx; x++) - arcbios_putcell(cpu, ' ', x, - cpu->machine->md.arc->console_cury); - } -} - - -/* - * arcbios_putchar(): - * - * If we're using X11 with VGA-style console, then output to that console. - * Otherwise, use console_putchar(). - */ -static void arcbios_putchar(struct cpu *cpu, int ch) -{ - int addr; - unsigned char byte; - - if (!cpu->machine->md.arc->vgaconsole) { - /* Text console output: */ - - /* Hack for Windows NT, which uses 0x9b instead of ESC + [ */ - if (ch == 0x9b) { - console_putchar(cpu->machine->main_console_handle, 27); - ch = '['; - } - console_putchar(cpu->machine->main_console_handle, ch); - return; - } - - if (cpu->machine->md.arc->in_escape_sequence) { - int len = strlen(cpu->machine->md.arc->escape_sequence); - cpu->machine->md.arc->escape_sequence[len] = ch; - len++; - if (len >= ARC_MAX_ESC) - len = ARC_MAX_ESC; - cpu->machine->md.arc->escape_sequence[len] = '\0'; - if ((ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z') || len >= ARC_MAX_ESC) { - handle_esc_seq(cpu); - cpu->machine->md.arc->in_escape_sequence = 0; - } - } else { - if (ch == 27) { - cpu->machine->md.arc->in_escape_sequence = 1; - cpu->machine->md.arc->escape_sequence[0] = '\0'; - } else if (ch == 0x9b) { - cpu->machine->md.arc->in_escape_sequence = 1; - cpu->machine->md.arc->escape_sequence[0] = '['; - cpu->machine->md.arc->escape_sequence[1] = '\0'; - } else if (ch == '\b') { - if (cpu->machine->md.arc->console_curx > 0) - cpu->machine->md.arc->console_curx --; - } else if (ch == '\r') { - cpu->machine->md.arc->console_curx = 0; - } else if (ch == '\n') { - cpu->machine->md.arc->console_cury ++; - } else if (ch == '\t') { - cpu->machine->md.arc->console_curx = - ((cpu->machine->md.arc->console_curx - 1) - | 7) + 1; - /* TODO: Print spaces? */ - } else { - /* Put char: */ - if (cpu->machine->md.arc->console_curx >= - cpu->machine->md.arc->console_maxx) { - cpu->machine->md.arc->console_curx = 0; - cpu->machine->md.arc->console_cury ++; - scroll_if_necessary(cpu); - } - arcbios_putcell(cpu, ch, - cpu->machine->md.arc->console_curx, - cpu->machine->md.arc->console_cury); - cpu->machine->md.arc->console_curx ++; - } - } - - scroll_if_necessary(cpu); - - /* Update cursor position: */ - addr = (cpu->machine->md.arc->console_curx >= - cpu->machine->md.arc->console_maxx? - cpu->machine->md.arc->console_maxx - 1 : - cpu->machine->md.arc->console_curx) + - cpu->machine->md.arc->console_cury * - cpu->machine->md.arc->console_maxx; - byte = 0x0e; - cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> - console_ctrlregs + 0x14, - &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); - byte = (addr >> 8) & 255; - cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> - console_ctrlregs + 0x15, - &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); - byte = 0x0f; - cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> - console_ctrlregs + 0x14, - &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); - byte = addr & 255; - cpu->memory_rw(cpu, cpu->mem, cpu->machine->md.arc-> - console_ctrlregs + 0x15, - &byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); -} - - -/* - * arcbios_putstring(): - */ -static void arcbios_putstring(struct cpu *cpu, const char *s) -{ - while (*s) { - if (*s == '\n') - arcbios_putchar(cpu, '\r'); - arcbios_putchar(cpu, *s++); - } -} - - -/* - * arcbios_register_scsicontroller(): - */ -void arcbios_register_scsicontroller(struct machine *machine, - uint64_t scsicontroller_component) -{ - machine->md.arc->scsicontroller = scsicontroller_component; -} - - -/* - * arcbios_get_scsicontroller(): - */ -uint64_t arcbios_get_scsicontroller(struct machine *machine) -{ - return machine->md.arc->scsicontroller; -} - - -/* - * arcbios_add_memory_descriptor(): - * - * NOTE: arctype is the ARC type, not the SGI type. This function takes - * care of converting, when necessary. - */ -void arcbios_add_memory_descriptor(struct cpu *cpu, - uint64_t base, uint64_t len, int arctype) -{ - uint64_t memdesc_addr; - int s; - struct arcbios_mem arcbios_mem; - struct arcbios_mem64 arcbios_mem64; - - if (verbose >= 2) - debug("arcbios_add_memory_descriptor: base=0x%llx len=0x%llx arctype=%i\n", - (long long)base, (long long)len, arctype); - - base /= 4096; - len /= 4096; - - /* - * TODO: Huh? Why isn't it necessary to convert from arc to sgi types? - * - * TODO 2: It seems that it _is_ necessary, but NetBSD's arcdiag - * doesn't handle the sgi case separately. - */ -#if 1 - if (cpu->machine->machine_type == MACHINE_SGI) { - /* arctype is SGI style */ - /* printf("%i => ", arctype); */ - switch (arctype) { - case 0: arctype = 0; break; - case 1: arctype = 1; break; - case 2: arctype = 3; break; - case 3: arctype = 4; break; - case 4: arctype = 5; break; - case 5: arctype = 6; break; - case 6: arctype = 7; break; - case 7: arctype = 2; break; - } - /* printf("%i\n", arctype); */ - } -#endif - if (cpu->machine->md.arc->arc_64bit) - s = sizeof(arcbios_mem64); - else - s = sizeof(arcbios_mem); - - memdesc_addr = cpu->machine->md.arc->memdescriptor_base + - cpu->machine->md.arc->n_memdescriptors * s; - - if (cpu->machine->md.arc->arc_64bit) { - memset(&arcbios_mem64, 0, s); - store_32bit_word_in_host(cpu, - (unsigned char *)&arcbios_mem64.Type, arctype); - store_64bit_word_in_host(cpu, - (unsigned char *)&arcbios_mem64.BasePage, base); - store_64bit_word_in_host(cpu, - (unsigned char *)&arcbios_mem64.PageCount, len); - store_buf(cpu, memdesc_addr, (char *)&arcbios_mem64, s); - } else { - memset(&arcbios_mem, 0, s); - store_32bit_word_in_host(cpu, - (unsigned char *)&arcbios_mem.Type, arctype); - store_32bit_word_in_host(cpu, - (unsigned char *)&arcbios_mem.BasePage, base); - store_32bit_word_in_host(cpu, - (unsigned char *)&arcbios_mem.PageCount, len); - store_buf(cpu, memdesc_addr, (char *)&arcbios_mem, s); - } - - cpu->machine->md.arc->n_memdescriptors ++; -} - - -/* - * arcbios_addchild(): - * - * host_tmp_component is a temporary component, with data formated for - * the host system. It needs to be translated/copied into emulated RAM. - * - * Return value is the virtual (emulated) address of the added component. - * - * TODO: This function doesn't care about memory management, but simply - * stores the new child after the last stored child. - * TODO: This stuff is really ugly. - */ -static uint64_t arcbios_addchild(struct cpu *cpu, - struct arcbios_component *host_tmp_component, - const char *identifier, uint32_t parent) -{ - struct machine *machine = cpu->machine; - uint64_t a = machine->md.arc->next_component_address; - uint32_t peer=0; - uint32_t child=0; - int n_left; - uint64_t peeraddr = FIRST_ARC_COMPONENT; - - /* - * This component has no children yet, but it may have peers (that is, - * other components that share this component's parent) so we have to - * set the peer value correctly. - * - * Also, if this is the first child of some parent, the parent's child - * pointer should be set to point to this component. (But only if it - * is the first.) - * - * This is really ugly: scan through all components, starting from - * FIRST_ARC_COMPONENT, to find a component with the same parent as - * this component will have. If such a component is found, and its - * 'peer' value is NULL, then set it to this component's address (a). - * - * TODO: make this nicer - */ - - n_left = machine->md.arc->n_components; - while (n_left > 0) { - /* Load parent, child, and peer values: */ - uint32_t eparent, echild, epeer, tmp; - unsigned char buf[4]; - - /* debug("[ addchild: peeraddr = 0x%08x ]\n", - (int)peeraddr); */ - - cpu->memory_rw(cpu, cpu->mem, - peeraddr + 0 * machine->md.arc->wordlen, &buf[0], - sizeof(eparent), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; - tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; - } - epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); - - cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * - machine->md.arc->wordlen, - &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; - tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; - } - echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); - - cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * - machine->md.arc->wordlen, - &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; - tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; - } - eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); - - /* debug(" epeer=%x echild=%x eparent=%x\n", - (int)epeer,(int)echild,(int)eparent); */ - - if ((uint32_t)eparent == (uint32_t)parent && - (uint32_t)epeer == 0) { - epeer = a; - store_32bit_word(cpu, peeraddr + 0x00, epeer); - /* debug("[ addchild: adding 0x%08x as peer " - "to 0x%08x ]\n", (int)a, (int)peeraddr); */ - } - if ((uint32_t)peeraddr == (uint32_t)parent && - (uint32_t)echild == 0) { - echild = a; - store_32bit_word(cpu, peeraddr + 0x04, echild); - /* debug("[ addchild: adding 0x%08x as " - "child to 0x%08x ]\n", (int)a, (int)peeraddr); */ - } - - /* Go to the next component: */ - cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x28, &buf[0], - sizeof(eparent), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; - tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; - } - - tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); - peeraddr += 0x30; - peeraddr += tmp + 1; - peeraddr = ((peeraddr - 1) | 3) + 1; - - n_left --; - } - - store_32bit_word(cpu, a + 0x00, peer); - store_32bit_word(cpu, a + 0x04, child); - store_32bit_word(cpu, a + 0x08, parent); - store_32bit_word(cpu, a+ 0x0c, host_tmp_component->Class); - store_32bit_word(cpu, a+ 0x10, host_tmp_component->Type); - store_32bit_word(cpu, a+ 0x14, host_tmp_component->Flags + - 65536 * host_tmp_component->Version); - store_32bit_word(cpu, a+ 0x18, host_tmp_component->Revision); - store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Key); - store_32bit_word(cpu, a+ 0x20, host_tmp_component->AffinityMask); - store_32bit_word(cpu, a+ 0x24, host_tmp_component-> - ConfigurationDataSize); - store_32bit_word(cpu, a+ 0x28, host_tmp_component->IdentifierLength); - store_32bit_word(cpu, a+ 0x2c, host_tmp_component->Identifier); - - machine->md.arc->next_component_address += 0x30; - - if (host_tmp_component->IdentifierLength != 0) { - store_32bit_word(cpu, a + 0x2c, a + 0x30); - store_string(cpu, a + 0x30, identifier); - if (identifier != NULL) - machine->md.arc->next_component_address += - strlen(identifier) + 1; - } - - machine->md.arc->next_component_address ++; - - /* Round up to next 0x4 bytes: */ - machine->md.arc->next_component_address = - ((machine->md.arc->next_component_address - 1) | 3) + 1; - - machine->md.arc->n_components ++; - - return a; -} - - -/* - * arcbios_addchild64(): - * - * host_tmp_component is a temporary component, with data formated for - * the host system. It needs to be translated/copied into emulated RAM. - * - * Return value is the virtual (emulated) address of the added component. - * - * TODO: This function doesn't care about memory management, but simply - * stores the new child after the last stored child. - * TODO: This stuff is really ugly. - */ -static uint64_t arcbios_addchild64(struct cpu *cpu, - struct arcbios_component64 *host_tmp_component, - const char *identifier, uint64_t parent) -{ - struct machine *machine = cpu->machine; - uint64_t a = machine->md.arc->next_component_address; - uint64_t peer=0; - uint64_t child=0; - int n_left; - uint64_t peeraddr = FIRST_ARC_COMPONENT; - - /* - * This component has no children yet, but it may have peers (that is, - * other components that share this component's parent) so we have to - * set the peer value correctly. - * - * Also, if this is the first child of some parent, the parent's child - * pointer should be set to point to this component. (But only if it - * is the first.) - * - * This is really ugly: scan through all components, starting from - * FIRST_ARC_COMPONENT, to find a component with the same parent as - * this component will have. If such a component is found, and its - * 'peer' value is NULL, then set it to this component's address (a). - * - * TODO: make this nicer - */ - - n_left = machine->md.arc->n_components; - while (n_left > 0) { - /* Load parent, child, and peer values: */ - uint64_t eparent, echild, epeer, tmp; - unsigned char buf[8]; - - /* debug("[ addchild: peeraddr = 0x%016" PRIx64" ]\n", - (uint64_t) peeraddr); */ - - cpu->memory_rw(cpu, cpu->mem, - peeraddr + 0 * machine->md.arc->wordlen, &buf[0], - sizeof(eparent), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; - tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; - tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; - tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; - } - epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) - + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) - + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); - - cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * - machine->md.arc->wordlen, - &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; - tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; - tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; - tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; - } - echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) - + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) - + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); - - cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * - machine->md.arc->wordlen, - &buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[7]; buf[7] = tmp2; - tmp2 = buf[1]; buf[1] = buf[6]; buf[6] = tmp2; - tmp2 = buf[2]; buf[2] = buf[5]; buf[5] = tmp2; - tmp2 = buf[3]; buf[3] = buf[4]; buf[4] = tmp2; - } - eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) - + ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) - + ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); - - /* debug(" epeer=%" PRIx64" echild=%" PRIx64" eparent=%" PRIx64 - "\n", (uint64_t) epeer, (uint64_t) echild, - (uint64_t) eparent); */ - - if (eparent == parent && epeer == 0) { - epeer = a; - store_64bit_word(cpu, peeraddr + 0 * - machine->md.arc->wordlen, epeer); - /* debug("[ addchild: adding 0x%016" PRIx64" as peer " - "to 0x%016" PRIx64" ]\n", (uint64_t) a, - (uint64_t) peeraddr); */ - } - if (peeraddr == parent && echild == 0) { - echild = a; - store_64bit_word(cpu, peeraddr + 1 * - machine->md.arc->wordlen, echild); - /* debug("[ addchild: adding 0x%016" PRIx64" as child " - "to 0x%016" PRIx64" ]\n", (uint64_t) a, - (uint64_t) peeraddr); */ - } - - /* Go to the next component: */ - cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x34, - &buf[0], sizeof(uint32_t), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp2; - tmp2 = buf[0]; buf[0] = buf[3]; buf[3] = tmp2; - tmp2 = buf[1]; buf[1] = buf[2]; buf[2] = tmp2; - } - tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); - - tmp &= 0xfffff; - - peeraddr += 0x50; - peeraddr += tmp + 1; - peeraddr = ((peeraddr - 1) | 3) + 1; - - n_left --; - } - - store_64bit_word(cpu, a + 0x00, peer); - store_64bit_word(cpu, a + 0x08, child); - store_64bit_word(cpu, a + 0x10, parent); - store_32bit_word(cpu, a+ 0x18, host_tmp_component->Class); - store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Type); - store_32bit_word(cpu, a+ 0x20, host_tmp_component->Flags); - store_32bit_word(cpu, a+ 0x24, host_tmp_component->Version + - ((uint64_t)host_tmp_component->Revision << 16)); - store_32bit_word(cpu, a+ 0x28, host_tmp_component->Key); - store_64bit_word(cpu, a+ 0x30, host_tmp_component->AffinityMask); - store_64bit_word(cpu, a+ 0x38, host_tmp_component-> - ConfigurationDataSize); - store_64bit_word(cpu, a+ 0x40, host_tmp_component->IdentifierLength); - store_64bit_word(cpu, a+ 0x48, host_tmp_component->Identifier); - - /* TODO: Find out how a REAL ARCS64 implementation does it. */ - - machine->md.arc->next_component_address += 0x50; - - if (host_tmp_component->IdentifierLength != 0) { - store_64bit_word(cpu, a + 0x48, a + 0x50); - store_string(cpu, a + 0x50, identifier); - if (identifier != NULL) - machine->md.arc->next_component_address += - strlen(identifier) + 1; - } - - machine->md.arc->next_component_address ++; - - /* Round up to next 0x8 bytes: */ - machine->md.arc->next_component_address = - ((machine->md.arc->next_component_address - 1) | 7) + 1; - - machine->md.arc->n_components ++; - return a; -} - - -/* - * arcbios_addchild_manual(): - * - * Used internally to set up component structures. - * Parent may only be NULL for the first (system) component. - * - * Return value is the virtual (emulated) address of the added component. - */ -uint64_t arcbios_addchild_manual(struct cpu *cpu, - uint64_t cclass, uint64_t type, uint64_t flags, - uint64_t version, uint64_t revision, uint64_t key, - uint64_t affinitymask, const char *identifier, uint64_t parent, - void *config_data, size_t config_len) -{ - struct machine *machine = cpu->machine; - /* This component is only for temporary use: */ - struct arcbios_component component; - struct arcbios_component64 component64; - - if (config_data != NULL) { - unsigned char *p = (unsigned char *) config_data; - size_t i; - - if (machine->md.arc->n_configuration_data >= MAX_CONFIG_DATA) { - printf("fatal error: you need to increase " - "MAX_CONFIG_DATA\n"); - exit(1); - } - - for (i=0; imemory_rw(cpu, cpu->mem, - machine->md.arc->configuration_data_next_addr + i, - &ch, 1, MEM_WRITE, CACHE_NONE); - } - - machine->md.arc->configuration_data_len[ - machine->md.arc->n_configuration_data] = config_len; - machine->md.arc->configuration_data_configdata[ - machine->md.arc->n_configuration_data] = - machine->md.arc->configuration_data_next_addr; - machine->md.arc->configuration_data_next_addr += config_len; - machine->md.arc->configuration_data_component[ - machine->md.arc->n_configuration_data] = - machine->md.arc->next_component_address + - (cpu->machine->md.arc->arc_64bit? 0x18 : 0x0c); - - /* printf("& ADDING %i: configdata=0x%016" PRIx64" " - "component=0x%016" PRIx64"\n", - machine->md.arc->n_configuration_data, - (uint64_t) machine->md.arc->configuration_data_configdata[ - machine->md.arc->n_configuration_data], - (uint64_t) machine->md.arc->configuration_data_component[ - machine->md.arc->n_configuration_data]); */ - - machine->md.arc->n_configuration_data ++; - } - - if (!cpu->machine->md.arc->arc_64bit) { - component.Class = cclass; - component.Type = type; - component.Flags = flags; - component.Version = version; - component.Revision = revision; - component.Key = key; - component.AffinityMask = affinitymask; - component.ConfigurationDataSize = config_len; - component.IdentifierLength = 0; - component.Identifier = 0; - if (identifier != NULL) { - component.IdentifierLength = strlen(identifier) + 1; - } - - return arcbios_addchild(cpu, &component, identifier, parent); - } else { - component64.Class = cclass; - component64.Type = type; - component64.Flags = flags; - component64.Version = version; - component64.Revision = revision; - component64.Key = key; - component64.AffinityMask = affinitymask; - component64.ConfigurationDataSize = config_len; - component64.IdentifierLength = 0; - component64.Identifier = 0; - if (identifier != NULL) { - component64.IdentifierLength = strlen(identifier) + 1; - } - - return arcbios_addchild64(cpu, &component64, identifier, - parent); - } -} - - -/* - * arcbios_get_msdos_partition_size(): - * - * This function tries to parse MSDOS-style partition tables on a disk - * image, and return the starting offset (counted in bytes), and the - * size, of a specific partition. - * - * NOTE: partition_nr is 1-based! - * - * TODO: This is buggy, it doesn't really handle extended partitions. - * - * See http://www.nondot.org/sabre/os/files/Partitions/Partitions.html - * for more info. - */ -static void arcbios_get_msdos_partition_size(struct machine *machine, - int disk_id, int disk_type, int partition_nr, uint64_t *start, - uint64_t *size) -{ - int res, i, partition_type, cur_partition = 0; - unsigned char sector[512]; - unsigned char buf[16]; - uint64_t offset = 0, st; - - /* Partition 0 is the entire disk image: */ - *start = 0; - *size = diskimage_getsize(machine, disk_id, disk_type); - if (partition_nr == 0) - return; - -ugly_goto: - *start = 0; *size = 0; - - /* printf("reading MSDOS partition from offset 0x%" PRIx64"\n", - (uint64_t) offset); */ - - res = diskimage_access(machine, disk_id, disk_type, 0, offset, - sector, sizeof(sector)); - if (!res) { - fatal("[ arcbios_get_msdos_partition_size(): couldn't " - "read the disk image, id %i, offset 0x%" PRIx64" ]\n", - disk_id, (uint64_t) offset); - return; - } - - if (sector[510] != 0x55 || sector[511] != 0xaa) { - fatal("[ arcbios_get_msdos_partition_size(): not an " - "MSDOS partition table ]\n"); - } - -#if 0 - /* Debug dump: */ - for (i=0; i<4; i++) { - int j; - printf(" partition %i: ", i+1); - for (j=0; j<16; j++) - printf(" %02x", sector[446 + i*16 + j]); - printf("\n"); - } -#endif - - for (i=0; i<4; i++) { - memmove(buf, sector + 446 + 16*i, 16); - - partition_type = buf[4]; - - if (partition_type == 0) - continue; - - st = (buf[8] + (buf[9] << 8) + (buf[10] << 16) + - (buf[11] << 24)) * 512; - - if (start != NULL) - *start = st; - if (size != NULL) - *size = (buf[12] + (buf[13] << 8) + (buf[14] << 16) + - (buf[15] << 24)) * 512; - - /* Extended DOS partition: */ - if (partition_type == 5) { - offset += st; - goto ugly_goto; - } - - /* Found the right partition? Then return. */ - cur_partition ++; - if (cur_partition == partition_nr) - return; - } - - fatal("[ partition(%i) NOT found ]\n", partition_nr); -} - - -/* - * arcbios_handle_to_disk_id_and_type(): - */ -static int arcbios_handle_to_disk_id_and_type(struct machine *machine, - int handle, int *typep) -{ - int id, cdrom; - const char *s; - - if (handle < 0 || handle >= ARC_MAX_HANDLES) - return -1; - - s = machine->md.arc->file_handle_string[handle]; - if (s == NULL) - return -1; - - /* - * s is something like "scsi(0)disk(0)rdisk(0)partition(0)". - * TODO: This is really ugly and hardcoded. - */ - - if (strncmp(s, "scsi(", 5) != 0 || strlen(s) < 13) - return -1; - - *typep = DISKIMAGE_SCSI; - - cdrom = (s[7] == 'c'); - id = cdrom? atoi(s + 13) : atoi(s + 12); - - return id; -} - - -/* - * arcbios_handle_to_start_and_size(): - */ -static void arcbios_handle_to_start_and_size(struct machine *machine, - int handle, uint64_t *start, uint64_t *size) -{ - const char *s = machine->md.arc->file_handle_string[handle]; - const char *s2; - int disk_id, disk_type; - - disk_id = arcbios_handle_to_disk_id_and_type(machine, - handle, &disk_type); - - if (disk_id < 0) - return; - - /* This works for "partition(0)": */ - *start = 0; - *size = diskimage_getsize(machine, disk_id, disk_type); - - s2 = strstr(s, "partition("); - if (s2 != NULL) { - int partition_nr = atoi(s2 + 10); - /* printf("partition_nr = %i\n", partition_nr); */ - if (partition_nr != 0) - arcbios_get_msdos_partition_size(machine, - disk_id, disk_type, partition_nr, start, size); - } -} - - -/* - * arcbios_getfileinformation(): - * - * Fill in a GetFileInformation struct in emulated memory, - * for a specific file handle. (This is used to get the size - * and offsets of partitions on disk images.) - */ -static int arcbios_getfileinformation(struct cpu *cpu) -{ - int handle = cpu->cd.mips.gpr[MIPS_GPR_A0]; - uint64_t addr = cpu->cd.mips.gpr[MIPS_GPR_A1]; - uint64_t start, size; - - arcbios_handle_to_start_and_size(cpu->machine, handle, &start, &size); - - store_64bit_word(cpu, addr + 0, 0); - store_64bit_word(cpu, addr + 8, size); - store_64bit_word(cpu, addr + 16, 0); - store_32bit_word(cpu, addr + 24, 1); - store_32bit_word(cpu, addr + 28, 0); - store_32bit_word(cpu, addr + 32, 0); - - /* printf("\n!!! size=0x%x start=0x%x\n", (int)size, (int)start); */ - - return ARCBIOS_ESUCCESS; -} - - -/* - * arcbios_private_emul(): - * - * TODO: This is probably SGI specific. (?) - * - * 0x04 get nvram table - */ -void arcbios_private_emul(struct cpu *cpu) -{ - int vector = cpu->pc & 0xfff; - - switch (vector) { - case 0x04: - debug("[ ARCBIOS PRIVATE get nvram table(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - default: - cpu_register_dump(cpu->machine, cpu, 1, 0x1); - debug("a0 points to: "); - dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); - debug("\n"); - fatal("ARCBIOS: unimplemented PRIVATE vector 0x%x\n", vector); - cpu->running = 0; - } -} - - -/* - * arcbios_emul(): ARCBIOS emulation - * - * 0x0c Halt() - * 0x10 PowerDown() - * 0x14 Restart() - * 0x18 Reboot() - * 0x1c EnterInteractiveMode() - * 0x20 ReturnFromMain() - * 0x24 GetPeer(node) - * 0x28 GetChild(node) - * 0x2c GetParent(node) - * 0x30 GetConfigurationData(config_data, node) - * 0x3c GetComponent(name) - * 0x44 GetSystemId() - * 0x48 GetMemoryDescriptor(void *) - * 0x50 GetTime() - * 0x54 GetRelativeTime() - * 0x5c Open(path, mode, &fileid) - * 0x60 Close(handle) - * 0x64 Read(handle, &buf, len, &actuallen) - * 0x6c Write(handle, buf, len, &returnlen) - * 0x70 Seek(handle, &offset, len) - * 0x78 GetEnvironmentVariable(char *) - * 0x7c SetEnvironmentVariable(char *, char *) - * 0x80 GetFileInformation(handle, buf) - * 0x88 FlushAllCaches() - * 0x90 GetDisplayStatus(uint32_t handle) - * 0x100 undocumented IRIX (?) - */ -int arcbios_emul(struct cpu *cpu) -{ - struct machine *machine = cpu->machine; - int vector = cpu->pc & 0xfff; - int i, j, handle; - unsigned char ch2; - unsigned char buf[40]; - - if (cpu->pc >= ARC_PRIVATE_ENTRIES && - cpu->pc < ARC_PRIVATE_ENTRIES + 100*sizeof(uint32_t)) { - arcbios_private_emul(cpu); - return 1; - } - - if (machine->md.arc->arc_64bit) - vector /= 2; - - /* Special case for reboot by jumping to 0xbfc00000: */ - if (vector == 0 && (cpu->pc & 0xffffffffULL) == 0xbfc00000ULL) - vector = 0x18; - - switch (vector) { - case 0x0c: /* Halt() */ - case 0x10: /* PowerDown() */ - case 0x14: /* Restart() */ - case 0x18: /* Reboot() */ - case 0x1c: /* EnterInteractiveMode() */ - case 0x20: /* ReturnFromMain() */ - debug("[ ARCBIOS Halt() or similar ]\n"); - /* Halt all CPUs. */ - for (i=0; incpus; i++) { - machine->cpus[i]->running = 0; - } - machine->exit_without_entering_debugger = 1; - break; - case 0x24: /* GetPeer(node) */ - if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { - /* NULL ptr argument: return NULL. */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - } else { - uint64_t peer; - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A0] - 3 * - machine->md.arc->wordlen, &buf[0], - machine->md.arc->wordlen, MEM_READ, CACHE_NONE); - if (machine->md.arc->arc_64bit) { - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp; tmp = buf[0]; - buf[0] = buf[7]; buf[7] = tmp; - tmp = buf[1]; buf[1] = buf[6]; - buf[6] = tmp; - tmp = buf[2]; buf[2] = buf[5]; - buf[5] = tmp; - tmp = buf[3]; buf[3] = buf[4]; - buf[4] = tmp; - } - peer = (uint64_t)buf[0] + ((uint64_t)buf[1]<<8) - + ((uint64_t)buf[2]<<16) - + ((uint64_t)buf[3]<<24) - + ((uint64_t)buf[4]<<32) - + ((uint64_t)buf[5]<<40) - + ((uint64_t)buf[6]<<48) - + ((uint64_t)buf[7]<<56); - } else { - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp; tmp = buf[0]; - buf[0] = buf[3]; buf[3] = tmp; - tmp = buf[1]; buf[1] = buf[2]; - buf[2] = tmp; - } - peer = buf[0] + (buf[1]<<8) + (buf[2]<<16) - + (buf[3]<<24); - } - - cpu->cd.mips.gpr[MIPS_GPR_V0] = peer? - (peer + 3 * machine->md.arc->wordlen) : 0; - if (!machine->md.arc->arc_64bit) - cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) - (int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; - } - debug("[ ARCBIOS GetPeer(node 0x%016" PRIx64"): 0x%016" PRIx64 - " ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); - break; - case 0x28: /* GetChild(node) */ - /* 0 for the root, non-0 for children: */ - if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) - cpu->cd.mips.gpr[MIPS_GPR_V0] = FIRST_ARC_COMPONENT - + machine->md.arc->wordlen * 3; - else { - uint64_t child = 0; - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A0] - 2 * - machine->md.arc->wordlen, &buf[0], machine-> - md.arc->wordlen, MEM_READ, CACHE_NONE); - if (machine->md.arc->arc_64bit) { - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp; tmp = buf[0]; - buf[0] = buf[7]; buf[7] = tmp; - tmp = buf[1]; buf[1] = buf[6]; - buf[6] = tmp; - tmp = buf[2]; buf[2] = buf[5]; - buf[5] = tmp; - tmp = buf[3]; buf[3] = buf[4]; - buf[4] = tmp; - } - child = (uint64_t)buf[0] + - ((uint64_t)buf[1]<<8) + - ((uint64_t)buf[2]<<16) + - ((uint64_t)buf[3]<<24) + - ((uint64_t)buf[4]<<32) + - ((uint64_t)buf[5]<<40) + - ((uint64_t)buf[6]<<48) + - ((uint64_t)buf[7]<<56); - } else { - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp; tmp = buf[0]; - buf[0] = buf[3]; buf[3] = tmp; - tmp = buf[1]; buf[1] = buf[2]; - buf[2] = tmp; - } - child = buf[0] + (buf[1]<<8) + (buf[2]<<16) + - (buf[3]<<24); - } - - cpu->cd.mips.gpr[MIPS_GPR_V0] = child? - (child + 3 * machine->md.arc->wordlen) : 0; - if (!machine->md.arc->arc_64bit) - cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) - (int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0]; - } - debug("[ ARCBIOS GetChild(node 0x%016" PRIx64"): 0x%016" - PRIx64" ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); - break; - case 0x2c: /* GetParent(node) */ - { - uint64_t parent; - - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A0] - 1 * machine-> - md.arc->wordlen, &buf[0], machine->md.arc->wordlen, - MEM_READ, CACHE_NONE); - - if (machine->md.arc->arc_64bit) { - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp; tmp = buf[0]; - buf[0] = buf[7]; buf[7] = tmp; - tmp = buf[1]; buf[1] = buf[6]; - buf[6] = tmp; - tmp = buf[2]; buf[2] = buf[5]; - buf[5] = tmp; - tmp = buf[3]; buf[3] = buf[4]; - buf[4] = tmp; - } - parent = (uint64_t)buf[0] + - ((uint64_t)buf[1]<<8) + - ((uint64_t)buf[2]<<16) + - ((uint64_t)buf[3]<<24) + - ((uint64_t)buf[4]<<32) + - ((uint64_t)buf[5]<<40) + - ((uint64_t)buf[6]<<48) + - ((uint64_t)buf[7]<<56); - } else { - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp; tmp = buf[0]; - buf[0] = buf[3]; buf[3] = tmp; - tmp = buf[1]; buf[1] = buf[2]; - buf[2] = tmp; - } - parent = buf[0] + (buf[1]<<8) + - (buf[2]<<16) + (buf[3]<<24); - } - - cpu->cd.mips.gpr[MIPS_GPR_V0] = parent? - (parent + 3 * machine->md.arc->wordlen) : 0; - if (!machine->md.arc->arc_64bit) - cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) - (int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; - } - debug("[ ARCBIOS GetParent(node 0x%016" PRIx64"): 0x%016" - PRIx64" ]\n", (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_V0]); - break; - case 0x30: /* GetConfigurationData(void *configdata, void *node) */ - /* fatal("[ ARCBIOS GetConfigurationData(0x%016" PRIx64"," - "0x%016" PRIx64") ]\n", - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; - for (i=0; imd.arc->n_configuration_data; i++) { - /* fatal("configuration_data_component[%i] = " - "0x%016" PRIx64"\n", i, (uint64_t) machine-> - md.arc->configuration_data_component[i]); */ - if (cpu->cd.mips.gpr[MIPS_GPR_A1] == - machine->md.arc->configuration_data_component[i]) { - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - for (j=0; j - md.arc->configuration_data_len[i]; j++) { - unsigned char ch; - cpu->memory_rw(cpu, cpu->mem, - machine->md.arc-> - configuration_data_configdata[i] + - j, &ch, 1, MEM_READ, CACHE_NONE); - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A0] + j, - &ch, 1, MEM_WRITE, CACHE_NONE); - } - break; - } - } - break; - case 0x3c: /* GetComponent(char *name) */ - debug("[ ARCBIOS GetComponent(\""); - dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); - debug("\") ]\n"); - - if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { - fatal("[ ARCBIOS GetComponent: NULL ptr ]\n"); - } else { - unsigned char buf2[500]; - int match_index = -1; - int match_len = 0; - - memset(buf2, 0, sizeof(buf2)); - for (i=0; i<(ssize_t)sizeof(buf2); i++) { - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A0] + i, - &buf2[i], 1, MEM_READ, CACHE_NONE); - if (buf2[i] == '\0') - i = sizeof(buf); - } - buf2[sizeof(buf2) - 1] = '\0'; - - /* "scsi(0)disk(0)rdisk(0)partition(0)" and such. */ - /* printf("GetComponent(\"%s\")\n", buf2); */ - - /* Default to NULL return value. */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - - /* Scan the string to component table: */ - for (i=0; imd.arc->n_string_to_components; - i++) { - int m = 0; - while (buf2[m] && machine->md.arc-> - string_to_component[i][m] && - machine->md.arc->string_to_component[i][m] - == buf2[m]) - m++; - if (m > match_len) { - match_len = m; - match_index = i; - } - } - - if (match_index >= 0) { - /* printf("Longest match: '%s'\n", - machine->md.arc->string_to_component[ - match_index]); */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = - machine->md.arc->string_to_component_value[ - match_index]; - } - } - break; - case 0x44: /* GetSystemId() */ - debug("[ ARCBIOS GetSystemId() ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = SGI_SYSID_ADDR; - break; - case 0x48: /* void *GetMemoryDescriptor(void *ptr) */ - debug("[ ARCBIOS GetMemoryDescriptor(0x%08x) ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - - /* If a0=NULL, then return the first descriptor: */ - if ((uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) - cpu->cd.mips.gpr[MIPS_GPR_V0] = - machine->md.arc->memdescriptor_base; - else { - int s = machine->md.arc->arc_64bit? - sizeof(struct arcbios_mem64) - : sizeof(struct arcbios_mem); - int nr = cpu->cd.mips.gpr[MIPS_GPR_A0] - - machine->md.arc->memdescriptor_base; - nr /= s; - nr ++; - cpu->cd.mips.gpr[MIPS_GPR_V0] = - machine->md.arc->memdescriptor_base + s * nr; - if (nr >= machine->md.arc->n_memdescriptors) - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - } - break; - case 0x50: /* GetTime() */ - debug("[ ARCBIOS GetTime() ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0xffffffff80001000ULL; - /* TODO! */ - break; - case 0x54: /* GetRelativeTime() */ - debug("[ ARCBIOS GetRelativeTime() ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t)time(NULL); - break; - case 0x5c: /* Open(char *path, uint32_t mode, uint32_t *fileID) */ - debug("[ ARCBIOS Open(\""); - dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); - debug("\",0x%x,0x%x)", (int)cpu->cd.mips.gpr[MIPS_GPR_A0], - (int)cpu->cd.mips.gpr[MIPS_GPR_A1], - (int)cpu->cd.mips.gpr[MIPS_GPR_A2]); - - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ENOENT; - - handle = 3; - /* TODO: Starting at 0 would require some updates... */ - while (machine->md.arc->file_handle_in_use[handle]) { - handle ++; - if (handle >= ARC_MAX_HANDLES) { - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EMFILE; - break; - } - } - - if (handle >= ARC_MAX_HANDLES) { - fatal("[ ARCBIOS Open: out of file handles ]\n"); - } else if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { - fatal("[ ARCBIOS Open: NULL ptr ]\n"); - } else { - /* - * TODO: This is hardcoded to successfully open - * anything. It is used by the Windows NT SETUPLDR - * program to load stuff from the boot partition. - */ - unsigned char *buf2; - CHECK_ALLOCATION(buf2 = (unsigned char *) malloc(MAX_OPEN_STRINGLEN)); - memset(buf2, 0, MAX_OPEN_STRINGLEN); - for (i=0; imemory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A0] + i, - &buf2[i], 1, MEM_READ, CACHE_NONE); - if (buf2[i] == '\0') - i = MAX_OPEN_STRINGLEN; - } - buf2[MAX_OPEN_STRINGLEN - 1] = '\0'; - machine->md.arc->file_handle_string[handle] = - (char *)buf2; - machine->md.arc->current_seek_offset[handle] = 0; - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; - } - - if (cpu->cd.mips.gpr[MIPS_GPR_V0] == ARCBIOS_ESUCCESS) { - debug(" = handle %i ]\n", (int)handle); - store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A2], - handle); - machine->md.arc->file_handle_in_use[handle] = 1; - } else - debug(" = ERROR %i ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_V0]); - break; - case 0x60: /* Close(uint32_t handle) */ - debug("[ ARCBIOS Close(%i) ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - if (!machine->md.arc->file_handle_in_use[cpu->cd.mips.gpr[ - MIPS_GPR_A0]]) { - fatal("ARCBIOS Close(%i): bad handle\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; - } else { - machine->md.arc->file_handle_in_use[ - cpu->cd.mips.gpr[MIPS_GPR_A0]] = 0; - // TODO: Yes, this is a memory leak. But it will be - // scrapped in favor of real code after the rewrite (I - // hope). - //if (machine->md.arc->file_handle_string[ - // cpu->cd.mips.gpr[MIPS_GPR_A0]] != NULL) - // free(machine->md.arc->file_handle_string[ - // cpu->cd.mips.gpr[MIPS_GPR_A0]]); - machine->md.arc->file_handle_string[cpu->cd.mips. - gpr[MIPS_GPR_A0]] = NULL; - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; - } - break; - case 0x64: /* Read(handle, void *buf, length, uint32_t *count) */ - if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { - int j2, nread = 0, a2; - - /* - * Before going into the loop, make sure stdout - * is flushed. If we're using an X11 VGA console, - * then it needs to be flushed as well. - */ - fflush(stdin); - fflush(stdout); - /* NOTE/TODO: This gives a tick to _everything_ */ - for (j2=0; j2tick_functions.n_entries; j2++) - machine->tick_functions.f[j2](cpu, - machine->tick_functions.extra[j2]); - - a2 = cpu->cd.mips.gpr[MIPS_GPR_A2]; - for (j2=0; j2main_console_handle); - if (x < 0) - return 0; - - /* - * ESC + '[' should be transformed into 0x9b: - * - * NOTE/TODO: This makes the behaviour of just - * pressing ESC a bit harder to define. - */ - if (x == 27) { - x = console_readchar(cpu-> - machine->main_console_handle); - if (x == '[' || x == 'O') - x = 0x9b; - } - - ch = x; - nread ++; - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A1] + j2, - &ch, 1, MEM_WRITE, CACHE_NONE); - - /* NOTE: Only one char, from STDIN: */ - j2 = cpu->cd.mips.gpr[MIPS_GPR_A2]; /* :-) */ - } - - store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], - nread); - /* TODO: not EAGAIN? */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = - nread? ARCBIOS_ESUCCESS: ARCBIOS_EAGAIN; - } else { - int handleTmp = cpu->cd.mips.gpr[MIPS_GPR_A0]; - int disk_type = 0; - int disk_id = arcbios_handle_to_disk_id_and_type( - machine, handleTmp, &disk_type); - uint64_t partition_offset = 0; - int res; - uint64_t size; /* dummy */ - unsigned char *tmp_buf; - - arcbios_handle_to_start_and_size(machine, handleTmp, - &partition_offset, &size); - - debug("[ ARCBIOS Read(%i,0x%08x,0x%08x,0x%08x) ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0], - (int)cpu->cd.mips.gpr[MIPS_GPR_A1], - (int)cpu->cd.mips.gpr[MIPS_GPR_A2], - (int)cpu->cd.mips.gpr[MIPS_GPR_A3]); - - CHECK_ALLOCATION(tmp_buf = (unsigned char *) - malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); - - res = diskimage_access(machine, disk_id, disk_type, - 0, partition_offset + machine->md.arc-> - current_seek_offset[handleTmp], tmp_buf, - cpu->cd.mips.gpr[MIPS_GPR_A2]); - - /* If the transfer was successful, transfer the - data to emulated memory: */ - if (res) { - uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; - store_buf(cpu, dst, (char *)tmp_buf, - cpu->cd.mips.gpr[MIPS_GPR_A2]); - store_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A3], - cpu->cd.mips.gpr[MIPS_GPR_A2]); - machine->md.arc->current_seek_offset[handleTmp] += - cpu->cd.mips.gpr[MIPS_GPR_A2]; - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - } else - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; - free(tmp_buf); - } - break; - case 0x68: /* GetReadStatus(handle) */ - /* - * According to arcbios_tty_getchar() in NetBSD's - * dev/arcbios/arcbios_tty.c, GetReadStatus should - * return 0 if there is something available. - * - * TODO: Error codes are things like ARCBIOS_EAGAIN. - */ - if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { - cpu->cd.mips.gpr[MIPS_GPR_V0] = console_charavail( - machine->main_console_handle)? 0 : 1; - } else { - fatal("[ ARCBIOS GetReadStatus(%i) from " - "something other than STDIN: TODO ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - /* TODO */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; - } - break; - case 0x6c: /* Write(handle, buf, len, &returnlen) */ - if (cpu->cd.mips.gpr[MIPS_GPR_A0] != ARCBIOS_STDOUT) { - /* - * TODO: this is just a test - */ - int handleTmp = cpu->cd.mips.gpr[MIPS_GPR_A0]; - int disk_type = 0; - int disk_id = arcbios_handle_to_disk_id_and_type( - machine, handleTmp, &disk_type); - uint64_t partition_offset = 0; - int res, tmpi; - uint64_t size; /* dummy */ - unsigned char *tmp_buf; - - arcbios_handle_to_start_and_size(machine, - handleTmp, &partition_offset, &size); - - debug("[ ARCBIOS Write(%i,0x%08" PRIx64",%i,0x%08" - PRIx64") ]\n", (int) cpu->cd.mips.gpr[MIPS_GPR_A0], - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1], - (int) cpu->cd.mips.gpr[MIPS_GPR_A2], - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A3]); - - CHECK_ALLOCATION(tmp_buf = (unsigned char *) - malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); - - for (tmpi=0; tmpi<(int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]; tmpi++) - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A1] + tmpi, - &tmp_buf[tmpi], sizeof(char), MEM_READ, - CACHE_NONE); - - res = diskimage_access(machine, disk_id, disk_type, - 1, partition_offset + machine->md.arc-> - current_seek_offset[handleTmp], tmp_buf, - cpu->cd.mips.gpr[MIPS_GPR_A2]); - - if (res) { - store_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A3], - cpu->cd.mips.gpr[MIPS_GPR_A2]); - machine->md.arc->current_seek_offset[handleTmp] += - cpu->cd.mips.gpr[MIPS_GPR_A2]; - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - } else - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; - free(tmp_buf); - } else { - for (i=0; i<(int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]; - i++) { - unsigned char ch = '\0'; - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A1] + i, - &ch, sizeof(ch), MEM_READ, CACHE_NONE); - - arcbios_putchar(cpu, ch); - } - } - store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], - cpu->cd.mips.gpr[MIPS_GPR_A2]); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ - break; - case 0x70: /* Seek(uint32_t handle, int64_t *ofs, - uint32_t whence): uint32_t */ - debug("[ ARCBIOS Seek(%i,0x%08" PRIx64",%i): ", - (int) cpu->cd.mips.gpr[MIPS_GPR_A0], - (uint64_t)cpu->cd.mips.gpr[MIPS_GPR_A1], - (int) cpu->cd.mips.gpr[MIPS_GPR_A2]); - - if (cpu->cd.mips.gpr[MIPS_GPR_A2] != 0) { - fatal("[ ARCBIOS Seek(%i,0x%08" PRIx64",%i): " - "UNIMPLEMENTED whence=%i ]\n", - (int) cpu->cd.mips.gpr[MIPS_GPR_A0], - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1], - (int) cpu->cd.mips.gpr[MIPS_GPR_A2], - (int) cpu->cd.mips.gpr[MIPS_GPR_A2]); - } - - { - unsigned char bufTmp[8]; - uint64_t ofs; - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A1], &bufTmp[0], - sizeof(bufTmp), MEM_READ, CACHE_NONE); - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - unsigned char tmp; - tmp = bufTmp[0]; bufTmp[0] = bufTmp[7]; bufTmp[7] = tmp; - tmp = bufTmp[1]; bufTmp[1] = bufTmp[6]; bufTmp[6] = tmp; - tmp = bufTmp[2]; bufTmp[2] = bufTmp[5]; bufTmp[5] = tmp; - tmp = bufTmp[3]; bufTmp[3] = bufTmp[4]; bufTmp[4] = tmp; - } - ofs = bufTmp[0] + (bufTmp[1] << 8) + (bufTmp[2] << 16) + - (bufTmp[3] << 24) + ((uint64_t)bufTmp[4] << 32) + - ((uint64_t)bufTmp[5] << 40) + ((uint64_t)bufTmp[6] << 48) - + ((uint64_t)bufTmp[7] << 56); - - machine->md.arc->current_seek_offset[ - cpu->cd.mips.gpr[MIPS_GPR_A0]] = ofs; - debug("%016" PRIx64" ]\n", (uint64_t) ofs); - } - - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ - - break; - case 0x78: /* GetEnvironmentVariable(char *) */ - /* Find the environment variable given by a0: */ - for (i=0; i<(ssize_t)sizeof(buf); i++) - cpu->memory_rw(cpu, cpu->mem, - cpu->cd.mips.gpr[MIPS_GPR_A0] + i, - &buf[i], sizeof(char), MEM_READ, CACHE_NONE); - buf[sizeof(buf)-1] = '\0'; - debug("[ ARCBIOS GetEnvironmentVariable(\"%s\") ]\n", buf); - for (i=0; i<0x1000; i++) { - /* Matching string at offset i? */ - int nmatches = 0; - uint64_t envptr = machine->machine_type == MACHINE_SGI ? ARC_ENV_STRINGS_SGI : ARC_ENV_STRINGS; - for (j=0; j<(ssize_t)strlen((char *)buf); j++) { - cpu->memory_rw(cpu, cpu->mem, - (uint64_t)(envptr + i + j), - &ch2, sizeof(char), MEM_READ, CACHE_NONE); - if (ch2 == buf[j]) - nmatches++; - } - cpu->memory_rw(cpu, cpu->mem, - (uint64_t)(envptr + i + - strlen((char *)buf)), &ch2, sizeof(char), - MEM_READ, CACHE_NONE); - if (nmatches == (int)strlen((char *)buf) && ch2=='=') { - cpu->cd.mips.gpr[MIPS_GPR_V0] = - envptr + i + - strlen((char *)buf) + 1; - return 1; - } - } - /* Return NULL if string wasn't found. */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x7c: /* SetEnvironmentVariable(char *, char *) */ - debug("[ ARCBIOS SetEnvironmentVariable(\""); - dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); - debug("\",\""); - dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1]); - debug("\") ]\n"); - /* TODO: This is a dummy. */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; - break; - case 0x80: /* GetFileInformation() */ - debug("[ ARCBIOS GetFileInformation(%i,0x%x): ", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0], - (int)cpu->cd.mips.gpr[MIPS_GPR_A1]); - - if (cpu->cd.mips.gpr[MIPS_GPR_A0] >= ARC_MAX_HANDLES) { - debug("invalid file handle ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; - } else if (!machine->md.arc->file_handle_in_use[cpu->cd. - mips.gpr[MIPS_GPR_A0]]) { - debug("file handle not in use! ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; - } else { - debug("'%s' ]\n", machine->md.arc->file_handle_string[ - cpu->cd.mips.gpr[MIPS_GPR_A0]]); - cpu->cd.mips.gpr[MIPS_GPR_V0] = - arcbios_getfileinformation(cpu); - } - break; - case 0x88: /* FlushAllCaches() */ - debug("[ ARCBIOS FlushAllCaches(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x90: /* void *GetDisplayStatus(handle) */ - debug("[ ARCBIOS GetDisplayStatus(%i) ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - /* TODO: handle different values of 'handle'? */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = ARC_DSPSTAT_ADDR; - break; - case 0x100: - /* - * Undocumented, used by IRIX. - */ - debug("[ ARCBIOS: IRIX 0x100 (?) ]\n"); - /* TODO */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x888: - /* - * Magical crash if there is no exception handling code. - */ - fatal("EXCEPTION, but no exception handler installed yet.\n"); - quiet_mode = 0; - cpu_register_dump(machine, cpu, 1, 0x1); - cpu->running = 0; - break; - default: - quiet_mode = 0; - cpu_register_dump(machine, cpu, 1, 0x1); - debug("a0 points to: "); - dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); - debug("\n"); - fatal("ARCBIOS: unimplemented vector 0x%x\n", vector); - cpu->running = 0; - } - - return 1; -} - - -/* - * arcbios_set_default_exception_handler(): - */ -void arcbios_set_default_exception_handler(struct cpu *cpu) -{ - /* - * The default exception handlers simply jump to 0xbfc88888, - * which is then taken care of in arcbios_emul() above. - * - * 3c1abfc8 lui k0,0xbfc8 - * 375a8888 ori k0,k0,0x8888 - * 03400008 jr k0 - * 00000000 nop - */ - store_32bit_word(cpu, 0xffffffff80000000ULL, 0x3c1abfc8); - store_32bit_word(cpu, 0xffffffff80000004ULL, 0x375a8888); - store_32bit_word(cpu, 0xffffffff80000008ULL, 0x03400008); - store_32bit_word(cpu, 0xffffffff8000000cULL, 0x00000000); - - store_32bit_word(cpu, 0xffffffff80000080ULL, 0x3c1abfc8); - store_32bit_word(cpu, 0xffffffff80000084ULL, 0x375a8888); - store_32bit_word(cpu, 0xffffffff80000088ULL, 0x03400008); - store_32bit_word(cpu, 0xffffffff8000008cULL, 0x00000000); - - store_32bit_word(cpu, 0xffffffff80000180ULL, 0x3c1abfc8); - store_32bit_word(cpu, 0xffffffff80000184ULL, 0x375a8888); - store_32bit_word(cpu, 0xffffffff80000188ULL, 0x03400008); - store_32bit_word(cpu, 0xffffffff8000018cULL, 0x00000000); -} - - -/* - * arcbios_add_other_components(): - * - * TODO: How should this be synched with the hardware devices - * added in machine.c? - */ -static void arcbios_add_other_components(struct machine *machine, - uint64_t system) -{ - struct cpu *cpu = machine->cpus[0]; - - if (machine->machine_type == MACHINE_ARC && - (machine->machine_subtype == MACHINE_ARC_JAZZ_PICA - || machine->machine_subtype == MACHINE_ARC_JAZZ_MAGNUM)) { - uint64_t jazzbus, ali_s3, vxl; - uint64_t diskcontroller, floppy, kbdctl, kbd; - uint64_t ptrctl, ptr, paral, audio; - uint64_t eisa, scsi; - /* uint64_t serial1, serial2; */ - - jazzbus = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_AdapterClass, - COMPONENT_TYPE_MultiFunctionAdapter, - 0, 1, 2, 0, 0xffffffff, "Jazz-Internal Bus", - system, NULL, 0); - - /* - * DisplayController, needed by NetBSD: - * TODO: NetBSD still doesn't use it :( - */ - switch (machine->machine_subtype) { - case MACHINE_ARC_JAZZ_PICA: - /* Default TLB entries on PICA-61: */ - - /* 7: 256K, asid: 0x0, v: 0xe1000000, - p0: 0xfff00000(2.VG), p1: 0x0(0..G) */ - mips_coproc_tlb_set_entry(cpu, 7, 262144, - 0xffffffffe1000000ULL, - 0x0fff00000ULL, 0, 1, 0, 0, 0, 1, 0, 2, 0); - - /* 8: 64K, asid: 0x0, v: 0xe0000000, - p0: 0x80000000(2DVG), p1: 0x0(0..G) */ - mips_coproc_tlb_set_entry(cpu, 8, 65536, - 0xffffffffe0000000ULL, - 0x080000000ULL, 0, 1, 0, 1, 0, 1, 0, 2, 0); - - /* 9: 64K, asid: 0x0, v: 0xe00e0000, - p0: 0x800e0000(2DVG), p1: 0x800f0000(2DVG) */ - mips_coproc_tlb_set_entry(cpu, 9, 65536, - (uint64_t)0xffffffffe00e0000ULL, - (uint64_t)0x0800e0000ULL, - (uint64_t)0x0800f0000ULL, 1, 1, 1, 1, 1, 0, 2, 2); - - /* 10: 4K, asid: 0x0, v: 0xe0100000, - p0: 0xf0000000(2DVG), p1: 0x0(0..G) */ - mips_coproc_tlb_set_entry(cpu, 10, 4096, - (uint64_t)0xffffffffe0100000ULL, - (uint64_t)0x0f0000000ULL, 0,1, 0, 1, 0, 1, 0, 2, 0); - - /* 11: 1M, asid: 0x0, v: 0xe0200000, - p0: 0x60000000(2DVG), p1: 0x60100000(2DVG) */ - mips_coproc_tlb_set_entry(cpu, 11, 1048576, - 0xffffffffe0200000ULL, - 0x060000000ULL, 0x060100000ULL,1,1,1,1,1, 0, 2, 2); - - /* 12: 1M, asid: 0x0, v: 0xe0400000, - p0: 0x60200000(2DVG), p1: 0x60300000(2DVG) */ - mips_coproc_tlb_set_entry(cpu, 12, 1048576, - 0xffffffffe0400000ULL, 0x060200000ULL, - 0x060300000ULL, 1, 1, 1, 1, 1, 0, 2, 2); - - /* 13: 4M, asid: 0x0, v: 0xe0800000, - p0: 0x40000000(2DVG), p1: 0x40400000(2DVG) */ - mips_coproc_tlb_set_entry(cpu, 13, 1048576*4, - 0xffffffffe0800000ULL, 0x040000000ULL, - 0x040400000ULL, 1, 1, 1, 1, 1, 0, 2, 2); - - /* 14: 16M, asid: 0x0, v: 0xe2000000, - p0: 0x90000000(2DVG), p1: 0x91000000(2DVG) */ - mips_coproc_tlb_set_entry(cpu, 14, 1048576*16, - 0xffffffffe2000000ULL, 0x090000000ULL, - 0x091000000ULL, 1, 1, 1, 1, 1, 0, 2, 2); - - if (machine->x11_md.in_use) { - ali_s3 = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_DisplayController, - COMPONENT_FLAG_ConsoleOut | - COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "ALI_S3", - jazzbus, NULL, 0); - - arcbios_addchild_manual(cpu, - COMPONENT_CLASS_PeripheralClass, - COMPONENT_TYPE_MonitorPeripheral, - COMPONENT_FLAG_ConsoleOut | - COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "1024x768", - ali_s3, NULL, 0); - } - break; - case MACHINE_ARC_JAZZ_MAGNUM: - if (machine->x11_md.in_use) { - vxl = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_DisplayController, - COMPONENT_FLAG_ConsoleOut | - COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "VXL", - jazzbus, NULL, 0); - - arcbios_addchild_manual(cpu, - COMPONENT_CLASS_PeripheralClass, - COMPONENT_TYPE_MonitorPeripheral, - COMPONENT_FLAG_ConsoleOut | - COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "1024x768", - vxl, NULL, 0); - } - break; - } - - diskcontroller = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_DiskController, - COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "I82077", jazzbus, NULL, 0); - - floppy = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_PeripheralClass, - COMPONENT_TYPE_FloppyDiskPeripheral, - COMPONENT_FLAG_Removable | - COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, NULL, diskcontroller, NULL, 0); - - kbdctl = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_KeyboardController, - COMPONENT_FLAG_ConsoleIn | COMPONENT_FLAG_Input, - 1, 2, 0, 0xffffffff, "I8742", jazzbus, NULL, 0); - - kbd = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_PeripheralClass, - COMPONENT_TYPE_KeyboardPeripheral, - COMPONENT_FLAG_ConsoleIn | COMPONENT_FLAG_Input, - 1, 2, 0, 0xffffffff, "PCAT_ENHANCED", kbdctl, NULL, 0); - - ptrctl = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_PointerController, COMPONENT_FLAG_Input, - 1, 2, 0, 0xffffffff, "I8742", jazzbus, NULL, 0); - - ptr = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_PeripheralClass, - COMPONENT_TYPE_PointerPeripheral, COMPONENT_FLAG_Input, - 1, 2, 0, 0xffffffff, "PS2 MOUSE", ptrctl, NULL, 0); - -/* These cause Windows NT to bug out. */ -#if 0 - serial1 = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_SerialController, - COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "COM1", jazzbus, NULL, 0); - - serial2 = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_SerialController, - COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "COM1", jazzbus, NULL, 0); -#endif - - paral = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_ParallelController, - COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "LPT1", jazzbus, NULL, 0); - - audio = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ControllerClass, - COMPONENT_TYPE_AudioController, - COMPONENT_FLAG_Input | COMPONENT_FLAG_Output, - 1, 2, 0, 0xffffffff, "MAGNUM", jazzbus, NULL, 0); - - eisa = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_AdapterClass, COMPONENT_TYPE_EISAAdapter, - 0, 1, 2, 0, 0xffffffff, "EISA", system, NULL, 0); - - { - unsigned char config[78]; - memset(config, 0, sizeof(config)); - -/* config data version: 1, revision: 2, count: 4 */ -config[0] = 0x01; config[1] = 0x00; -config[2] = 0x02; config[3] = 0x00; -config[4] = 0x04; config[5] = 0x00; config[6] = 0x00; config[7] = 0x00; - -/* - type: Interrupt - share_disposition: DeviceExclusive, flags: LevelSensitive - level: 4, vector: 22, reserved1: 0 -*/ - config[8] = arc_CmResourceTypeInterrupt; - config[9] = arc_CmResourceShareDeviceExclusive; - config[10] = arc_CmResourceInterruptLevelSensitive; - config[12] = 4; - config[16] = 22; - config[20] = 0; - -/* - type: Memory - share_disposition: DeviceExclusive, flags: ReadWrite - start: 0x 0 80002000, length: 0x1000 -*/ - config[24] = arc_CmResourceTypeMemory; - config[25] = arc_CmResourceShareDeviceExclusive; - config[26] = arc_CmResourceMemoryReadWrite; -config[28] = 0x00; config[29] = 0x20; config[30] = 0x00; config[31] = 0x80; - config[32] = 0x00; config[33] = 0x00; config[34] = 0x00; config[35] = 0x00; -config[36] = 0x00; config[37] = 0x10; config[38] = 0x00; config[39] = 0x00; - -/* - type: DMA - share_disposition: DeviceExclusive, flags: 0x0 - channel: 0, port: 0, reserved1: 0 -*/ - config[40] = arc_CmResourceTypeDMA; - config[41] = arc_CmResourceShareDeviceExclusive; -/* 42..43 = flags, 44,45,46,47 = channel, 48,49,50,51 = port, 52,53,54,55 - = reserved */ - -/* type: DeviceSpecific - share_disposition: DeviceExclusive, flags: 0x0 - datasize: 6, reserved1: 0, reserved2: 0 - data: [0x1:0x0:0x2:0x0:0x7:0x30] -*/ - config[56] = arc_CmResourceTypeDeviceSpecific; - config[57] = arc_CmResourceShareDeviceExclusive; -/* 58,59 = flags 60,61,62,63 = data size, 64..71 = reserved */ - config[60] = 6; -/* 72..77 = the data */ - config[72] = 0x01; config[73] = 0x00; config[74] = 0x02; - config[75] = 0x00; config[76] = 0x07; config[77] = 0x30; - scsi = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_AdapterClass, - COMPONENT_TYPE_SCSIAdapter, - 0, 1, 2, 0, 0xffffffff, "ESP216", - system, config, sizeof(config)); - - arcbios_register_scsicontroller(machine, scsi); - } - } -} - - -/* - * arcbios_console_init(): - * - * Called from machine.c whenever an ARC-based machine is running with - * a graphical VGA-style framebuffer, which can be used as console. - */ -void arcbios_console_init(struct machine *machine, - uint64_t vram, uint64_t ctrlregs) -{ - if (machine->md.arc == NULL) { - CHECK_ALLOCATION(machine->md.arc = (struct machine_arcbios *) - malloc(sizeof(struct machine_arcbios))); - memset(machine->md.arc, 0, sizeof(struct machine_arcbios)); - } - - machine->md.arc->vgaconsole = 1; - - machine->md.arc->console_vram = vram; - machine->md.arc->console_ctrlregs = ctrlregs; - machine->md.arc->console_maxx = ARC_CONSOLE_MAX_X; - machine->md.arc->console_maxy = ARC_CONSOLE_MAX_Y; - machine->md.arc->in_escape_sequence = 0; - machine->md.arc->escape_sequence[0] = '\0'; -} - - -/* - * arc_environment_setup(): - * - * Initialize the emulated environment variables. - */ -static void arc_environment_setup(struct machine *machine, int is64bit, - const char *primary_ether_addr) -{ - size_t bootpath_len = 500; - char *init_bootpath; - uint64_t addr, addr2; - struct cpu *cpu = machine->cpus[0]; - - /* - * Boot string in ARC format: - * - * TODO: How about floppies? multi()disk()fdisk() - * Is tftp() good for netbooting? - */ - CHECK_ALLOCATION(init_bootpath = (char *) malloc(bootpath_len)); - init_bootpath[0] = '\0'; - - if (machine->bootdev_id < 0 || machine->force_netboot) { - snprintf(init_bootpath, bootpath_len, "tftp()"); - } else { - /* TODO: Make this nicer. */ - if (machine->machine_type == MACHINE_SGI) { - if (machine->machine_subtype == 30) - strlcat(init_bootpath, "xio(0)pci(15)", - bootpath_len); - if (machine->machine_subtype == 32) - strlcat(init_bootpath, "pci(0)", - bootpath_len); - } - - if (diskimage_is_a_cdrom(machine, machine->bootdev_id, - machine->bootdev_type)) - snprintf(init_bootpath + strlen(init_bootpath), - bootpath_len - strlen(init_bootpath), - "scsi(0)cdrom(%i)fdisk(0)", machine->bootdev_id); - else - snprintf(init_bootpath + strlen(init_bootpath), - bootpath_len - strlen(init_bootpath), - "scsi(0)disk(%i)rdisk(0)partition(1)", - machine->bootdev_id); - } - - if (machine->machine_type == MACHINE_ARC) - strlcat(init_bootpath, "\\", bootpath_len); - - CHECK_ALLOCATION(machine->bootstr = (char *) malloc(ARC_BOOTSTR_BUFLEN)); - - strlcpy(machine->bootstr, init_bootpath, ARC_BOOTSTR_BUFLEN); - if (strlcat(machine->bootstr, machine->boot_kernel_filename, - ARC_BOOTSTR_BUFLEN) >= ARC_BOOTSTR_BUFLEN) { - fprintf(stderr, "boot string too long?\n"); - exit(1); - } - - /* Boot args., eg "-a" */ - machine->bootarg = machine->boot_string_argument; - - /* argc, argv, envp in a0, a1, a2: */ - cpu->cd.mips.gpr[MIPS_GPR_A0] = 0; /* note: argc is increased later */ - - /* TODO: not needed? */ - cpu->cd.mips.gpr[MIPS_GPR_SP] = (int64_t)(int32_t) - (machine->physical_ram_in_mb * 1048576 + 0x80000000 - 0x2080); - - /* Set up argc/argv: */ - addr = ARC_ENV_STRINGS; - addr2 = ARC_ARGV_START; - cpu->cd.mips.gpr[MIPS_GPR_A1] = addr2; - - /* bootstr: */ - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, machine->bootstr, &addr); - cpu->cd.mips.gpr[MIPS_GPR_A0] ++; - - /* bootarg: */ - if (machine->bootarg[0] != '\0') { - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, machine->bootarg, &addr); - cpu->cd.mips.gpr[MIPS_GPR_A0] ++; - } - - store_pointer_and_advance(cpu, &addr2, 0, is64bit); - - cpu->cd.mips.gpr[MIPS_GPR_A2] = addr2; - - if (machine->machine_type == MACHINE_SGI) { - /* - * The SGI O2 PROM contains an "env" section header like this: - * - * 00004000 00 00 00 00 00 00 00 00 53 48 44 52 00 00 04 00 |........SHDR....| - * 00004010 03 03 00 00 65 6e 76 00 00 00 00 00 00 00 00 00 |....env.........| - * 00004020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| - * 00004030 00 00 00 00 31 2e 30 00 00 00 00 00 13 18 11 ae |....1.0.........| - * - * followed by environment variables at 0x4000. It is not required - * by NetBSD/OpenBSD/Linux, but Irix seems to hardcodedly look into - * the PROM address space for this header. - */ - store_32bit_word(cpu, ARC_ENV_SGI + 0x08, 0x53484452); - store_32bit_word(cpu, ARC_ENV_SGI + 0x0c, 0x00000400); - store_32bit_word(cpu, ARC_ENV_SGI + 0x10, 0x03030000); - store_32bit_word(cpu, ARC_ENV_SGI + 0x14, 0x656e7600); - store_32bit_word(cpu, ARC_ENV_SGI + 0x34, 0x312e3000); - store_32bit_word(cpu, ARC_ENV_SGI + 0x3c, 0x131811ae); - addr = ARC_ENV_STRINGS_SGI; - } - - /* - * Add environment variables. For each variable, add it - * as a string using add_environment_string(), and add a - * pointer to it to the ARC_ENV_POINTERS array. - */ - if (machine->machine_type == MACHINE_SGI) { - if (machine->x11_md.in_use) { - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "ConsoleIn=keyboard()", - &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "ConsoleOut=video()", - &addr); - - /* g for graphical mode. G for graphical mode - with SGI logo visible on Irix? */ - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "console=g", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "gfx=alive", &addr); - } else { - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "ConsoleIn=serial(0)", - &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "ConsoleOut=serial(0)", - &addr); - - /* 'd' or 'd2' in Irix, 'ttyS0' in Linux? */ - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "console=d", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "gfx=dead", &addr); - } - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "AutoLoad=No", &addr); - - if (machine->bootdev_id < 0 || machine->force_netboot) { - /* - * diskless=1 means boot from network disk? (nfs?) - * diskless=2 means boot from network tape? - */ - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "diskless=1", &addr); - - // store_pointer_and_advance(cpu, &addr2, addr, is64bit); - // add_environment_string(cpu, "tapedevice=bootp()10.0.0.2:/dev/tape", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "bootfile=bootp()10.0.0.2:/var/boot/client/unix", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "SystemPartition=bootp()10.0.0.2:/var/boot/client", - &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "root=xyz", - &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "OSLoadPartition=bootp()10.0.0.2:/var/boot/client", - &addr); - } else { - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "diskless=0", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "SystemPartition=pci(0)scsi(0)disk(2)rdisk(0)partition(8)", - &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "OSLoadPartition=pci(0)scsi(0)disk(2)rdisk(0)partition(0)", - &addr); - } - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "volume=80", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "sgilogo=y", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "monitor=h", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "TimeZone=GMT", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "nogfxkbd=1", &addr); - - /* TODO IP30: 'xio(0)pci(15)scsi(0)disk(1)rdisk(0)partition(0)' */ - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "OSLoadFilename=/unix", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "OSLoader=sash", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "kernname=unix", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "rbaud=9600", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "rebound=y", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "crt_option=1", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "netaddr=10.0.0.1", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "netmask=255.0.0.0", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "dlserver=10.0.0.2", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "srvaddr=10.0.0.2", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "keybd=US", &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "cpufreq=3", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "dbaud=9600", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, primary_ether_addr, &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "verbose=1", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - // showconfig 0 means don't show. 1 means show some. - // 2 means show more. TODO: higher values? - add_environment_string(cpu, "showconfig=255", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "diagmode=v", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, "debug_bigmem=1", &addr); - } else { - char *tmp; - size_t mlen = ARC_BOOTSTR_BUFLEN; - CHECK_ALLOCATION(tmp = (char *) malloc(mlen)); - snprintf(tmp, mlen, "OSLOADOPTIONS=%s", machine->bootarg); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, tmp, &addr); - - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - snprintf(tmp, mlen, - "OSLOADPARTITION=scsi(0)disk(%d)rdisk(0)partition(1)", - machine->bootdev_id); - add_environment_string(cpu, tmp, &addr); - free(tmp); - - if (machine->x11_md.in_use) { - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "CONSOLEIN=multi()key()keyboard()console()", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "CONSOLEOUT=multi()video()monitor()console()", - &addr); - } else { - /* TODO: serial console for ARC? */ - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "CONSOLEIN=multi()serial(0)", &addr); - store_pointer_and_advance(cpu, &addr2, addr, is64bit); - add_environment_string(cpu, - "CONSOLEOUT=multi()serial(0)", &addr); - } - } - - /* End the environment strings with an empty zero-terminated - string, and the envp array with a NULL pointer. */ - add_environment_string(cpu, "", &addr); /* the end */ - store_pointer_and_advance(cpu, &addr2, 0, is64bit); - - /* Return address: (0x20 = ReturnFromMain()) */ - cpu->cd.mips.gpr[MIPS_GPR_RA] = ARC_FIRMWARE_ENTRIES + 0x20; -} - - -/* - * arcbios_init(): - * - * Should be called before any other arcbios function is used. An exception - * is arcbios_console_init(), which may be called before this function. - * - * TODO: Refactor; this is too long. - */ -void arcbios_init(struct machine *machine, int is64bit, uint64_t sgi_ram_offset, - const char *primary_ether_addr, uint8_t *primary_ether_macaddr) -{ - int i, alloclen = 20; - char *name; - uint64_t arc_reserved, mem_base; - struct cpu *cpu = machine->cpus[0]; - struct arcbios_sysid arcbios_sysid; - struct arcbios_dsp_stat arcbios_dsp_stat; - uint64_t system = 0; - struct arcbios_spb arcbios_spb; - struct arcbios_spb_64 arcbios_spb_64; - - if (machine->md.arc == NULL) { - CHECK_ALLOCATION(machine->md.arc = (struct machine_arcbios *) - malloc(sizeof(struct machine_arcbios))); - memset(machine->md.arc, 0, sizeof(struct machine_arcbios)); - } - - machine->md.arc->arc_64bit = is64bit; - machine->md.arc->wordlen = is64bit? sizeof(uint64_t) : sizeof(uint32_t); - - machine->md.arc->next_component_address = FIRST_ARC_COMPONENT; - machine->md.arc->configuration_data_next_addr = ARC_CONFIG_DATA_ADDR; - - if (machine->physical_ram_in_mb < 16) - fprintf(stderr, "WARNING! The ARC platform specification " - "doesn't allow less than 16 MB of RAM. Continuing " - "anyway.\n"); - - /* File handles 0, 1, and 2 are stdin, stdout, and stderr. */ - for (i=0; imd.arc->file_handle_in_use[i] = i<3? 1 : 0; - machine->md.arc->file_handle_string[i] = i>=3? NULL : - (i==0? "(stdin)" : (i==1? "(stdout)" : "(stderr)")); - machine->md.arc->current_seek_offset[i] = 0; - } - - if (!machine->x11_md.in_use) - machine->md.arc->vgaconsole = 0; - - if (machine->md.arc->vgaconsole) { - char tmpstr[100]; - int x, y; - - machine->md.arc->console_curcolor = 0x1f; - for (y=0; ymd.arc->console_maxy; y++) - for (x=0; xmd.arc->console_maxx; x++) - arcbios_putcell(cpu, ' ', x, y); - - machine->md.arc->console_curx = 0; - machine->md.arc->console_cury = 0; - - arcbios_putstring(cpu, "GXemul " VERSION" ARCBIOS emulation\n"); - - snprintf(tmpstr, sizeof(tmpstr), "%i cpu%s (%s), %i MB " - "memory\n\n", machine->ncpus, machine->ncpus > 1? "s" : "", - cpu->cd.mips.cpu_type.name, - machine->physical_ram_in_mb); - arcbios_putstring(cpu, tmpstr); - } - - arcbios_set_default_exception_handler(cpu); - - memset(&arcbios_sysid, 0, sizeof(arcbios_sysid)); - if (machine->machine_type == MACHINE_SGI) { - /* Vendor ID, max 8 chars: */ - strncpy(arcbios_sysid.VendorId, "SGI", 3); - switch (machine->machine_subtype) { - case 22: - strncpy(arcbios_sysid.ProductId, - "87654321", 8); /* some kind of ID? */ - break; - case 32: - strncpy(arcbios_sysid.ProductId, "8", 1); - /* 6 or 8 (?) */ - break; - default: - snprintf(arcbios_sysid.ProductId, 8, "IP%i", - machine->machine_subtype); - } - } else { - switch (machine->machine_subtype) { - case MACHINE_ARC_JAZZ_PICA: - strncpy(arcbios_sysid.VendorId, "MIPS MAG", 8); - strncpy(arcbios_sysid.ProductId, "ijkl", 4); - break; - case MACHINE_ARC_JAZZ_MAGNUM: - strncpy(arcbios_sysid.VendorId, "MIPS MAG", 8); - strncpy(arcbios_sysid.ProductId, "ijkl", 4); - break; - default: - fatal("error in machine.c sysid\n"); - exit(1); - } - } - - store_buf(cpu, SGI_SYSID_ADDR, (char *)&arcbios_sysid, - sizeof(arcbios_sysid)); - - arcbios_get_dsp_stat(cpu, &arcbios_dsp_stat); - store_buf(cpu, ARC_DSPSTAT_ADDR, (char *)&arcbios_dsp_stat, - sizeof(arcbios_dsp_stat)); - - /* - * The first 12 MBs of RAM are simply reserved... this simplifies - * things a lot. If there's more than 512MB of RAM, it has to be - * split in two, according to the ARC spec. - * - * However, the region of physical address space between 0x10000000 - * and 0x1fffffff (256 - 512 MB) is sometimes occupied by memory - * mapped devices, for example in the SGI O2, so that portion can not - * be used. - * - * Instead, any high memory needs to be added using a machine-specific - * high address. - */ - int reserved_bottom_mem_in_mb = 12; - int free_type = ARCBIOS_MEM_FreeMemory; - - machine->md.arc->memdescriptor_base = ARC_MEMDESC_ADDR; - - arc_reserved = 0x2000; - if (machine->machine_type == MACHINE_SGI) - arc_reserved = 0x4000; - - arcbios_add_memory_descriptor(cpu, 0, arc_reserved, - ARCBIOS_MEM_FirmwarePermanent); - arcbios_add_memory_descriptor(cpu, sgi_ram_offset + arc_reserved, - 0x60000-arc_reserved, ARCBIOS_MEM_FirmwareTemporary); - - uint64_t ram = 0; - - // Default is to use a physical memory base around zero (0). - mem_base = sgi_ram_offset / 1048576; - - while (ram < machine->physical_ram_in_mb) { - uint64_t to_add = machine->physical_ram_in_mb - ram; - - if (to_add > 256) - to_add = 256; - - if (ram == 0) { - // Skip first few MB of RAM, for reserved structures. - ram += reserved_bottom_mem_in_mb; - mem_base += reserved_bottom_mem_in_mb; - to_add -= reserved_bottom_mem_in_mb; - } - - arcbios_add_memory_descriptor(cpu, mem_base * 1048576, - to_add * 1048576, free_type); - - ram += to_add; - mem_base += to_add; - - if (mem_base == 256) { - if (machine->machine_type == MACHINE_SGI && - machine->machine_subtype == 32) { - // mem_base = 0x50000000 / 1048576; - // Actually, the above does not seem to work. - // Perhaps the ARCS in the O2 simply says - // 256 MB regardless of how much more there - // is in the machine? - break; - } else { - fatal("Ignoring RAM above 256 MB! (Not yet " - "implemented for this machine type.)\n"); - break; - } - } - } - - /* - * Components: (this is an example of what a system could look like) - * - * [System] - * [CPU] (one for each cpu) - * [FPU] (one for each cpu) - * [CPU Caches] - * [Memory] - * [Ethernet] - * [Serial] - * [SCSI] - * [Disk] - * - * Here's a good list of what hardware is in different IP-models: - * http://www.linux-mips.org/archives/linux-mips/2001-03/msg00101.html - */ - - if (machine->machine_name == NULL) - fatal("ERROR: machine_name == NULL\n"); - - /* Add the root node: */ - switch (machine->machine_type) { - case MACHINE_SGI: - CHECK_ALLOCATION(name = (char *) malloc(alloclen)); - snprintf(name, alloclen, "SGI-IP%i", - machine->machine_subtype); - - /* A very special case for IP24 (which identifies itself - as an IP22): */ - if (machine->machine_subtype == 24) - snprintf(name, alloclen, "SGI-IP22"); - break; - case MACHINE_ARC: - /* ARC: */ - switch (machine->machine_subtype) { - case MACHINE_ARC_JAZZ_PICA: - name = strdup("PICA-61"); - break; - case MACHINE_ARC_JAZZ_MAGNUM: - name = strdup("Microsoft-Jazz"); - break; - default: - fatal("Unimplemented ARC machine type %i\n", - machine->machine_subtype); - exit(1); - } - break; - default: - fatal("ERROR: non-SGI and non-ARC?\n"); - exit(1); - } - - system = arcbios_addchild_manual(cpu, COMPONENT_CLASS_SystemClass, - COMPONENT_TYPE_ARC, 0,1,2,0, 0xffffffff, name, 0/*ROOT*/, NULL, 0); - debug("ARC system @ 0x%" PRIx64" (\"%s\")\n", (uint64_t) system, name); - - - /* - * Add tree nodes for CPUs and their caches: - */ - - for (i=0; incpus; i++) { - uint64_t cpuaddr, fpu=0, picache, pdcache, sdcache=0; - int cache_size, cache_line_size; - unsigned int jj; - char arc_cpu_name[100]; - char arc_fpc_name[105]; - - snprintf(arc_cpu_name, sizeof(arc_cpu_name), - "MIPS-%s", machine->cpu_name); - - arc_cpu_name[sizeof(arc_cpu_name)-1] = 0; - for (jj=0; jj= 'a' && arc_cpu_name[jj] <= 'z') - arc_cpu_name[jj] += ('A' - 'a'); - - strlcpy(arc_fpc_name, arc_cpu_name, sizeof(arc_fpc_name)); - strlcat(arc_fpc_name, "FPC", sizeof(arc_fpc_name)); - - cpuaddr = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ProcessorClass, COMPONENT_TYPE_CPU, - 0, 1, 2, i, 0xffffffff, arc_cpu_name, system, NULL, 0); - - /* - * TODO: This was in the ARC specs, but it isn't really used - * by ARC implementations? At least SGI-IP32 uses it. - */ - if (machine->machine_type == MACHINE_SGI) - fpu = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_ProcessorClass, COMPONENT_TYPE_FPU, - 0, 1, 2, 0, 0xffffffff, arc_fpc_name, cpuaddr, - NULL, 0); - - cache_size = DEFAULT_PCACHE_SIZE - 12; - if (cpu->cd.mips.cache_picache) - cache_size = cpu->cd.mips.cache_picache - 12; - if (cache_size < 0) - cache_size = 0; - - cache_line_size = DEFAULT_PCACHE_LINESIZE; - if (cpu->cd.mips.cache_picache_linesize) - cache_line_size = cpu->cd.mips.cache_picache_linesize; - if (cache_line_size < 0) - cache_line_size = 0; - - picache = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_CacheClass, COMPONENT_TYPE_PrimaryICache, - 0, 1, 2, - /* - * Key bits: 0xXXYYZZZZ - * XX is refill-size. - * Cache line size is 1 << YY, - * Cache size is 4KB << ZZZZ. - */ - 0x01000000 + (cache_line_size << 16) + cache_size, - /* 32 bytes per line, default = 32 KB total */ - 0xffffffff, NULL, cpuaddr, NULL, 0); - - cache_size = DEFAULT_PCACHE_SIZE - 12; - if (cpu->cd.mips.cache_pdcache) - cache_size = cpu->cd.mips.cache_pdcache - 12; - if (cache_size < 0) - cache_size = 0; - - cache_line_size = DEFAULT_PCACHE_LINESIZE; - if (cpu->cd.mips.cache_pdcache_linesize) - cache_line_size = cpu->cd.mips.cache_pdcache_linesize; - if (cache_line_size < 0) - cache_line_size = 0; - - pdcache = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_CacheClass, - COMPONENT_TYPE_PrimaryDCache, 0, 1, 2, - /* - * Key bits: 0xYYZZZZ - * Cache line size is 1 << YY, - * Cache size is 4KB << ZZZZ. - */ - 0x01000000 + (cache_line_size << 16) + cache_size, - /* 32 bytes per line, default = 32 KB total */ - 0xffffffff, NULL, cpuaddr, NULL, 0); - - if (cpu->cd.mips.cache_secondary >= 12) { - cache_size = cpu->cd.mips.cache_secondary - 12; - - cache_line_size = 6; /* 64 bytes default */ - if (cpu->cd.mips.cache_secondary_linesize) - cache_line_size = cpu->cd.mips. - cache_secondary_linesize; - if (cache_line_size < 0) - cache_line_size = 0; - - sdcache = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_CacheClass, - COMPONENT_TYPE_SecondaryDCache, 0, 1, 2, - /* - * Key bits: 0xYYZZZZ - * Cache line size is 1 << YY, - * Cache size is 4KB << ZZZZ. - */ - 0x01000000 + (cache_line_size << 16) + cache_size, - /* 64 bytes per line, default = 1 MB total */ - 0xffffffff, NULL, cpuaddr, NULL, 0); - } - - debug("ARC cpu%i @ 0x%" PRIx64, i, (uint64_t) cpuaddr); - - if (fpu != 0) - debug(" (fpu @ 0x%" PRIx64")\n", (uint64_t) fpu); - else - debug("\n"); - - debug(" picache @ 0x%" PRIx64", pdcache @ 0x%" PRIx64"\n", - (uint64_t) picache, (uint64_t) pdcache); - - if (cpu->cd.mips.cache_secondary >= 12) - debug(" sdcache @ 0x%" PRIx64"\n", - (uint64_t) sdcache); - - if (machine->machine_type == MACHINE_SGI) { - /* TODO: Memory amount (and base address?)! */ - uint64_t memory = arcbios_addchild_manual(cpu, - COMPONENT_CLASS_MemoryClass, - COMPONENT_TYPE_MemoryUnit, 0, 1, 2, 0, - 0xffffffff, "memory", cpuaddr, NULL, 0); - debug("ARC memory @ 0x%" PRIx64"\n", (uint64_t) memory); - } - } - - - /* - * Add other components: - * - * TODO: How should this be synched with the hardware devices - * added in machine.c? - */ - - arcbios_add_other_components(machine, system); - - - /* - * Defalt TLB entry for 64-bit SGI machines: - */ - if (machine->machine_type == MACHINE_SGI) { - switch (machine->machine_subtype) { - case 12: - /* TODO: Not on 12? */ - break; - case 32: - /* Not needed for SGI O2? */ - break; - default: - mips_coproc_tlb_set_entry(cpu, 0, 1048576*16, - 0xc000000000000000ULL, 0, 1048576*16, 1,1,1,1,1, 0, 2, 2); - } - } - - - /* - * Set up Firmware Vectors: - */ - add_symbol_name(&machine->symbol_context, - ARC_FIRMWARE_ENTRIES, 0x10000, "[ARCBIOS entry]", 0, 1); - - for (i=0; i<100; i++) { - if (is64bit) { - store_64bit_word(cpu, ARC_FIRMWARE_VECTORS + i*8, - ARC_FIRMWARE_ENTRIES + i*8); - store_64bit_word(cpu, ARC_PRIVATE_VECTORS + i*8, - ARC_PRIVATE_ENTRIES + i*8); - - /* "Magic trap" instruction: */ - store_32bit_word(cpu, ARC_FIRMWARE_ENTRIES + i*8, - 0x00c0de0c); - store_32bit_word(cpu, ARC_PRIVATE_ENTRIES + i*8, - 0x00c0de0c); - } else { - store_32bit_word(cpu, ARC_FIRMWARE_VECTORS + i*4, - ARC_FIRMWARE_ENTRIES + i*4); - store_32bit_word(cpu, ARC_PRIVATE_VECTORS + i*4, - ARC_PRIVATE_ENTRIES + i*4); - - /* "Magic trap" instruction: */ - store_32bit_word(cpu, ARC_FIRMWARE_ENTRIES + i*4, - 0x00c0de0c); - store_32bit_word(cpu, ARC_PRIVATE_ENTRIES + i*4, - 0x00c0de0c); - } - } - - - /* - * Set up the ARC SPD: - */ - if (is64bit) { - /* ARCS64 SPD (TODO: This is just a guess) */ - memset(&arcbios_spb_64, 0, sizeof(arcbios_spb_64)); - store_64bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb_64.SPBSignature, ARCBIOS_SPB_SIGNATURE); - store_16bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb_64.Version, 64); - store_16bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb_64.Revision, 0); - store_64bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb_64.FirmwareVector, ARC_FIRMWARE_VECTORS); - store_buf(cpu, SGI_SPB_ADDR, (char *)&arcbios_spb_64, - sizeof(arcbios_spb_64)); - } else { - /* ARCBIOS SPB: (For ARC and 32-bit SGI modes) */ - memset(&arcbios_spb, 0, sizeof(arcbios_spb)); - store_32bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.SPBSignature, ARCBIOS_SPB_SIGNATURE); - store_32bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.SPBLength, sizeof(arcbios_spb)); - store_16bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.Version, 1); - store_16bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.Revision, machine->machine_type == - MACHINE_SGI? 10 : 2); - store_32bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.FirmwareVector, ARC_FIRMWARE_VECTORS); - store_32bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.FirmwareVectorLength, 100 * 4); /* ? */ - store_32bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.PrivateVector, ARC_PRIVATE_VECTORS); - store_32bit_word_in_host(cpu, (unsigned char *) - &arcbios_spb.PrivateVectorLength, 100 * 4); /* ? */ - store_buf(cpu, SGI_SPB_ADDR, (char *)&arcbios_spb, - sizeof(arcbios_spb)); - } - - - /* - * TODO: How to build the component tree intermixed with - * the rest of device initialization? - */ - - arc_environment_setup(machine, is64bit, primary_ether_addr); -} - diff -Nru gxemul-0.6.2/src/promemul/dec_prom.c gxemul-0.7.0+dfsg/src/promemul/dec_prom.c --- gxemul-0.6.2/src/promemul/dec_prom.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/dec_prom.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2003-2021 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: DECstation PROM emulation + * + * Implementation note: Remember that only the lowest 32 bits of GPRs are + * actually valid when using dyntrans with e.g. R3000 CPUs. + */ + +#include +#include +#include +#include +#include +#include + +#include "console.h" +#include "cpu.h" +#include "cpu_mips.h" +#include "diskimage.h" +#include "machine.h" +#include "machine_pmax.h" +#include "memory.h" +#include "misc.h" + +#include "thirdparty/dec_prom.h" +#include "thirdparty/dec_5100.h" +#include "thirdparty/dec_kn01.h" +#include "thirdparty/dec_kn02.h" +#include "thirdparty/dec_kn03.h" + + +extern int quiet_mode; + + +/* + * mem_readchar(): + * + * Reads a byte from emulated RAM, using a MIPS register as a base address. + * (Helper function.) + */ +static unsigned char mem_readchar(struct cpu *cpu, int regbase, int offset) +{ + unsigned char ch; + cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[regbase] + + offset, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); + return ch; +} + + +/* + * dec_jumptable_func(): + * + * The jumptable is located at the beginning of the PROM, at 0xbfc00000 + i*8, + * where i is the decimal function number. Many of these can be converted to + * an identical callback function. + * + * Return value is non-zero if the vector number was converted into a callback + * function number, otherwise 0. + * + * Vector (dec) Function + * 0x0 0 reset() + * 0x10 2 restart() + * 0x18 3 reinit() + * 0x30 6 open() + * 0x38 7 read() + * 0x58 11 lseek() + * 0x68 13 putchar() + * 0x88 17 printf() + * 0x108 33 getenv2() + */ +int dec_jumptable_func(struct cpu *cpu, int vector) +{ + int i; + static int file_opened = 0; + static int current_file_offset = 0; + + switch (vector) { + case 0x0: /* reset() */ + /* TODO */ + cpu->running = 0; + break; + case 0x10: /* restart() */ + /* TODO */ + cpu->running = 0; + break; + case 0x18: /* reinit() */ + /* TODO */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x30: /* open() */ + /* + * TODO: This is just a hack to allow Sprite/pmax' bootblock + * code to load /vmsprite. The filename argument (in A0) + * is ignored, and a file handle value of 1 is returned. + */ + if (file_opened) { + fatal("\ndec_jumptable_func(): opening more than one " + "file isn't supported yet.\n"); + cpu->running = 0; + } + file_opened = 1; + cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; + break; + case 0x38: /* read(handle, ptr, length) */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = (uint64_t) -1; + if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) { + int disk_id = diskimage_bootdev(cpu->machine, NULL); + int res; + unsigned char *tmp_buf; + + CHECK_ALLOCATION(tmp_buf = (unsigned char *) + malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); + + res = diskimage_access(cpu->machine, disk_id, + DISKIMAGE_SCSI, 0, current_file_offset, tmp_buf, + cpu->cd.mips.gpr[MIPS_GPR_A2]); + + /* If the transfer was successful, transfer the data + to emulated memory: */ + if (res) { + uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; + store_buf(cpu, dst, (char *)tmp_buf, + cpu->cd.mips.gpr[MIPS_GPR_A2]); + cpu->cd.mips.gpr[MIPS_GPR_V0] = + cpu->cd.mips.gpr[MIPS_GPR_A2]; + current_file_offset += + cpu->cd.mips.gpr[MIPS_GPR_A2]; + } + + free(tmp_buf); + } + break; + case 0x58: /* lseek(handle, offset[, whence]) */ + /* TODO */ + if (cpu->cd.mips.gpr[MIPS_GPR_A2] == 0) + current_file_offset = cpu->cd.mips.gpr[MIPS_GPR_A1]; + else + fatal("WARNING! Unimplemented whence in " + "dec_jumptable_func()\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x68: /* putchar() */ + console_putchar(cpu->machine->main_console_handle, + cpu->cd.mips.gpr[MIPS_GPR_A0]); + break; + case 0x88: /* printf() */ + return 0x30; + case 0x108: /* getenv2() */ + return 0x64; + default: + cpu_register_dump(cpu->machine, cpu, 1, 0x1); + printf("a0 points to: "); + for (i=0; i<40; i++) { + unsigned char ch = '\0'; + cpu->memory_rw(cpu, cpu->mem, + (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch, + sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); + if (ch >= ' ' && ch < 126) + printf("%c", ch); + else + printf("[%02x]", ch); + } + printf("\n"); + fatal("PROM emulation: unimplemented JUMP TABLE vector " + "0x%x (decimal function %i)\n", vector, vector/8); + cpu->running = 0; + } + + return 0; +} + + +/* + * decstation_prom_emul(): + * + * DECstation PROM emulation. + * + * Callback functions: + * 0x0c strcmp() + * 0x14 strlen() + * 0x24 getchar() + * 0x28 gets() + * 0x2c puts() + * 0x30 printf() + * 0x38 iopoll() + * 0x54 bootinit() + * 0x58 bootread() + * 0x64 getenv() + * 0x6c slot_address() + * 0x70 wbflush() + * 0x7c clear_cache() + * 0x80 getsysid() + * 0x84 getbitmap() + * 0x88 disableintr() + * 0x8c enableintr() + * 0x9c halt() + * 0xa4 gettcinfo() + * 0xa8 execute_cmd() + * 0xac rex() + */ +int decstation_prom_emul(struct cpu *cpu) +{ + int i, j, ch, argreg, argdata; + int vector = cpu->pc & 0xfff; + int callback = (cpu->pc & 0xf000)? 1 : 0; + unsigned char buf[100]; + unsigned char ch1, ch2; + uint64_t slot_base = 0x10000000, slot_size = 0; + + if (!callback) { + vector = dec_jumptable_func(cpu, vector); + if (vector == 0) + return 1; + } else { + /* Vector number is n*4, PC points to n*8. */ + vector /= 2; + } + + switch (vector) { + case 0x0c: /* strcmp(): */ + i = j = 0; + do { + ch1 = mem_readchar(cpu, MIPS_GPR_A0, i++); + ch2 = mem_readchar(cpu, MIPS_GPR_A1, j++); + } while (ch1 == ch2 && ch1 != '\0'); + + /* If ch1=='\0', then strings are equal. */ + if (ch1 == '\0') + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + if ((signed char)ch1 > (signed char)ch2) + cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; + if ((signed char)ch1 < (signed char)ch2) + cpu->cd.mips.gpr[MIPS_GPR_V0] = (uint64_t) -1; + break; + case 0x14: /* strlen(): */ + i = 0; + do { + ch2 = mem_readchar(cpu, MIPS_GPR_A0, i++); + } while (ch2 != 0); + cpu->cd.mips.gpr[MIPS_GPR_V0] = i - 1; + break; + case 0x24: /* getchar() */ + /* debug("[ DEC PROM getchar() ]\n"); */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar( + cpu->machine->main_console_handle); + break; + case 0x28: /* gets() */ + /* debug("[ DEC PROM gets() ]\n"); */ + // tmpaddr = cpu->cd.mips.gpr[MIPS_GPR_A0]; + i = 0; + + do { + /* TODO: Make this not hang (block) the entire emulator */ + while ((ch = console_readchar(cpu->machine->main_console_handle)) < 1) + ; + + if (ch == '\r') + ch = '\n'; + + ch2 = ch; + + if (ch == '\b') { + if (i > 0) { + console_putchar(cpu->machine->main_console_handle, ch2); + console_putchar(cpu->machine->main_console_handle, ' '); + console_putchar(cpu->machine->main_console_handle, ch2); + } + } else + console_putchar(cpu->machine->main_console_handle, ch2); + + fflush(stdout); + + if (ch == '\n') { + /* It seems that trailing newlines are not included in the buffer. */ + } else if (ch != '\b') { + cpu->memory_rw(cpu, cpu->mem, (int32_t) + cpu->cd.mips.gpr[MIPS_GPR_A0] + i, + &ch2, sizeof(ch2), MEM_WRITE, + CACHE_DATA | NO_EXCEPTIONS); + i++; + } else { + if (i > 0) + i--; + } + } while (ch2 != '\n'); + + /* Trailing nul-byte: */ + ch2 = '\0'; + cpu->memory_rw(cpu, cpu->mem, (int32_t) + cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch2, sizeof(ch2), + MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS); + + /* Return the input argument: */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = cpu->cd.mips.gpr[MIPS_GPR_A0]; + break; + case 0x2c: /* puts() */ + i = 0; + while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0') + console_putchar(cpu->machine->main_console_handle, ch); + console_putchar(cpu->machine->main_console_handle, '\n'); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x30: /* printf() */ + if (cpu->machine->register_dump || + cpu->machine->instruction_trace) + debug("PROM printf(0x%08lx): \n", + (long)cpu->cd.mips.gpr[MIPS_GPR_A0]); + + i = 0; ch = -1; argreg = MIPS_GPR_A1; + while (ch != '\0') { + char printfbuf[8000]; + size_t x; + + printfbuf[0] = printfbuf[sizeof(printfbuf)-1] = '\0'; + + ch = mem_readchar(cpu, MIPS_GPR_A0, i++); + switch (ch) { + case '%': + ch = '0'; + while (ch >= '0' && ch <= '9') + ch = mem_readchar(cpu, + MIPS_GPR_A0, i++); + + switch (ch) { + case '%': + strlcpy(printfbuf, "%%", + sizeof(printfbuf)); + break; + case 'c': + case 'd': + case 's': + case 'x': + /* Get argument: */ + if (argreg > MIPS_GPR_A3) { +#if 1 + /* Linux booters seem to go + over the edge sometimes: */ + ch = '\0'; + strlcpy(printfbuf, "[...]\n", + sizeof(printfbuf)); +#else + printf("[ decstation_prom_emul" + "(): too many arguments ]"); + /* This reuses the last arg, + which is utterly incorrect. + (TODO) */ + argreg = MIPS_GPR_A3; +#endif + } + + ch2 = argdata = cpu->cd.mips.gpr[argreg]; + + switch (ch) { + case 'c': + snprintf(printfbuf, sizeof( + printfbuf), "%c", ch2); + break; + case 'd': + snprintf(printfbuf, sizeof( + printfbuf), "%d", argdata); + break; + case 'x': + snprintf(printfbuf, sizeof( + printfbuf), "%x", argdata); + break; + case 's': + /* Print a "%s" string. */ + j = 0; + while (ch2) { + ch2 = mem_readchar(cpu, argreg, j++); + if (ch2) { + snprintf( + printfbuf + strlen(printfbuf), + sizeof(printfbuf) - 1 - strlen(printfbuf), + "%c", + ch2); + } + } + break; + } + argreg ++; + break; + default: + printf("[ unknown printf format char '%c' ]", ch); + } + break; + case '\0': + break; + default: + snprintf(printfbuf, sizeof(printfbuf), + "%c", ch); + } + + printfbuf[sizeof(printfbuf)-1] = '\0'; + + for (x=0; xmachine-> + main_console_handle, printfbuf[x]); + } + if (cpu->machine->register_dump || + cpu->machine->instruction_trace) + debug("\n"); + fflush(stdout); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x54: /* bootinit() */ + /* debug("[ DEC PROM bootinit(0x%08x): TODO ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x58: /* bootread(int b, void *buffer, int n) */ + /* + * Read data from the boot device. + * b is a sector number (512 bytes per sector), + * buffer is the destination address, and n + * is the number of _bytes_ to read. + * + * TODO: Return value? NetBSD thinks that 0 is ok. + */ + debug("[ DEC PROM bootread(0x%x, 0x%08x, 0x%x) ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0], + (int)cpu->cd.mips.gpr[MIPS_GPR_A1], + (int)cpu->cd.mips.gpr[MIPS_GPR_A2]); + + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + + if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) { + int disk_id = diskimage_bootdev(cpu->machine, NULL); + int res; + unsigned char *tmp_buf; + + CHECK_ALLOCATION(tmp_buf = (unsigned char *) + malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); + + res = diskimage_access(cpu->machine, disk_id, + DISKIMAGE_SCSI, 0, + cpu->cd.mips.gpr[MIPS_GPR_A0] * 512, tmp_buf, + cpu->cd.mips.gpr[MIPS_GPR_A2]); + + /* If the transfer was successful, transfer the data + to emulated memory: */ + if (res) { + uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; + if (dst < 0x80000000ULL) + dst |= 0x80000000; + + store_buf(cpu, dst, (char *)tmp_buf, + cpu->cd.mips.gpr[MIPS_GPR_A2]); + cpu->cd.mips.gpr[MIPS_GPR_V0] = + cpu->cd.mips.gpr[MIPS_GPR_A2]; + } + + free(tmp_buf); + } + break; + case 0x64: /* getenv() */ + /* Find the environment variable given by a0: */ + for (i=0; i<(int)sizeof(buf); i++) + cpu->memory_rw(cpu, cpu->mem, (int32_t) + cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf[i], + sizeof(char), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); + buf[sizeof(buf)-1] = '\0'; + debug("[ DEC PROM getenv(\"%s\") ]\n", buf); + for (i=0; i<0x1000; i++) { + /* Matching string at offset i? */ + int nmatches = 0; + for (j=0; j<(int32_t)strlen((char *)buf); j++) { + cpu->memory_rw(cpu, cpu->mem, (int32_t) + (DEC_PROM_STRINGS + i + j), &ch2, + sizeof(char), MEM_READ, CACHE_DATA | + NO_EXCEPTIONS); + if (ch2 == buf[j]) + nmatches++; + } + cpu->memory_rw(cpu, cpu->mem, (int32_t)(DEC_PROM_STRINGS + + i + strlen((char *)buf)), &ch2, sizeof(char), + MEM_READ, CACHE_DATA | NO_EXCEPTIONS); + if (nmatches == (int)strlen((char *)buf) && ch2=='=') { + cpu->cd.mips.gpr[MIPS_GPR_V0] = + DEC_PROM_STRINGS + i + + strlen((char *)buf) + 1; + return 1; + } + } + /* Return NULL if string wasn't found. */ + fatal("[ DEC PROM getenv(\"%s\"): WARNING: Not in " + "environment! ]\n", buf); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x6c: /* ulong slot_address(int sn) */ + debug("[ DEC PROM slot_address(%i) ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + /* TODO: This is too hardcoded. */ + /* TODO 2: Should these be physical or virtual addresses? */ + switch (cpu->machine->machine_subtype) { + case MACHINE_DEC_3MAX_5000: + slot_base = KN02_PHYS_TC_0_START;/* 0x1e000000 */ + slot_size = 4*1048576; /* 4 MB */ + break; + case MACHINE_DEC_3MIN_5000: + slot_base = 0x10000000; + slot_size = 0x4000000; /* 64 MB */ + break; + case MACHINE_DEC_3MAXPLUS_5000: + slot_base = 0x1e000000; + slot_size = 0x800000; /* 8 MB */ + break; + case MACHINE_DEC_MAXINE_5000: + slot_base = 0x10000000; + slot_size = 0x4000000; /* 64 MB */ + break; + default: + fatal("warning: DEC PROM slot_address() " + "unimplemented for this machine type\n"); + } + cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t) + (0x80000000 + slot_base + slot_size * + cpu->cd.mips.gpr[MIPS_GPR_A0]); + break; + case 0x70: /* wbflush() */ + debug("[ DEC PROM wbflush(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x7c: /* clear_cache(addr, len) */ + debug("[ DEC PROM clear_cache(0x%x,%i) ]\n", + (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0], + (int)cpu->cd.mips.gpr[MIPS_GPR_A1]); + /* TODO */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* ? */ + break; + case 0x80: /* getsysid() */ + /* debug("[ DEC PROM getsysid() ]\n"); */ + /* TODO: why did I add the 0x82 stuff??? */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = ((uint32_t)0x82 << 24) + + (cpu->machine->machine_subtype << 16) + (0x3 << 8); + cpu->cd.mips.gpr[MIPS_GPR_V0] = + (int64_t)(int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0]; + break; + case 0x84: /* getbitmap() */ + debug("[ DEC PROM getbitmap(0x%08x) ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + store_buf(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0], + (char *)cpu->machine->md.pmax->memmap, + sizeof(struct dec_memmap)); + cpu->cd.mips.gpr[MIPS_GPR_V0] = + sizeof(cpu->machine->md.pmax->memmap->bitmap); + break; + case 0x88: /* disableintr() */ + debug("[ DEC PROM disableintr(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x8c: /* enableintr() */ + debug("[ DEC PROM enableintr(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0x9c: /* halt() */ + debug("[ DEC PROM halt() ]\n"); + cpu->running = 0; + break; + case 0xa4: /* gettcinfo() */ + /* + * These are just bogus values... TODO + * + * 0: revision + * 4: clock period in nano seconds + * 8: slot size in megabytes TODO: not same for all models! + * 12: I/O timeout in cycles + * 16: DMA address range in megabytes + * 20: maximum DMA burst length + * 24: turbochannel parity (yes = 1) + * 28: reserved + */ + store_32bit_word(cpu, DEC_PROM_TCINFO + 0, 0); + store_32bit_word(cpu, DEC_PROM_TCINFO + 4, 50); + store_32bit_word(cpu, DEC_PROM_TCINFO + 8, 4); + store_32bit_word(cpu, DEC_PROM_TCINFO + 12, 10); + store_32bit_word(cpu, DEC_PROM_TCINFO + 16, 1); + store_32bit_word(cpu, DEC_PROM_TCINFO + 20, 100); + store_32bit_word(cpu, DEC_PROM_TCINFO + 24, 0); + store_32bit_word(cpu, DEC_PROM_TCINFO + 28, 0); + cpu->cd.mips.gpr[MIPS_GPR_V0] = DEC_PROM_TCINFO; + break; + case 0xa8: /* int execute_cmd(char *) */ + i = 0; + while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0') + console_putchar(cpu->machine->main_console_handle, ch); + console_putchar(cpu->machine->main_console_handle, '\n'); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 0xac: /* rex() */ + debug("[ DEC PROM rex('%c') ]\n", + (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); + switch ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0]) { + case 'h': + debug("DEC PROM: rex('h') ==> halt\n"); + cpu->running = 0; + break; + case 'b': + debug("DEC PROM: rex('b') ==> reboot: TODO " + "(halting CPU instead)\n"); + cpu->running = 0; + break; + default: + fatal("DEC prom emulation: unknown rex() a0=0x%" PRIx64 + " ('%c')\n", + (int64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], + (char) cpu->cd.mips.gpr[MIPS_GPR_A0]); + cpu->running = 0; + } + break; + default: + cpu_register_dump(cpu->machine, cpu, 1, 0x1); + printf("a0 points to: "); + for (i=0; i<40; i++) { + unsigned char chTmp = '\0'; + cpu->memory_rw(cpu, cpu->mem, (int32_t) + cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &chTmp, + sizeof(chTmp), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); + if (chTmp >= ' ' && chTmp < 126) + printf("%c", chTmp); + else + printf("[%02x]", chTmp); + } + printf("\n"); + fatal("PROM emulation: unimplemented callback vector 0x%x\n", + vector); + cpu->running = 0; + } + + return 1; +} + diff -Nru gxemul-0.6.2/src/promemul/dec_prom.cc gxemul-0.7.0+dfsg/src/promemul/dec_prom.cc --- gxemul-0.6.2/src/promemul/dec_prom.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/dec_prom.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,676 +0,0 @@ -/* - * Copyright (C) 2003-2009 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: DECstation PROM emulation - * - * Implementation note: Remember that only the lowest 32 bits of GPRs are - * actually valid when using dyntrans with e.g. R3000 CPUs. - */ - -#include -#include -#include -#include -#include -#include - -#include "console.h" -#include "cpu.h" -#include "cpu_mips.h" -#include "diskimage.h" -#include "machine.h" -#include "machine_pmax.h" -#include "memory.h" -#include "misc.h" - -#include "thirdparty/dec_prom.h" -#include "thirdparty/dec_5100.h" -#include "thirdparty/dec_kn01.h" -#include "thirdparty/dec_kn02.h" -#include "thirdparty/dec_kn03.h" - - -extern int quiet_mode; - - -/* - * mem_readchar(): - * - * Reads a byte from emulated RAM, using a MIPS register as a base address. - * (Helper function.) - */ -static unsigned char mem_readchar(struct cpu *cpu, int regbase, int offset) -{ - unsigned char ch; - cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[regbase] + - offset, &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); - return ch; -} - - -/* - * dec_jumptable_func(): - * - * The jumptable is located at the beginning of the PROM, at 0xbfc00000 + i*8, - * where i is the decimal function number. Many of these can be converted to - * an identical callback function. - * - * Return value is non-zero if the vector number was converted into a callback - * function number, otherwise 0. - * - * Vector (dec) Function - * 0x0 0 reset() - * 0x10 2 restart() - * 0x18 3 reinit() - * 0x30 6 open() - * 0x38 7 read() - * 0x58 11 lseek() - * 0x68 13 putchar() - * 0x88 17 printf() - * 0x108 33 getenv2() - */ -int dec_jumptable_func(struct cpu *cpu, int vector) -{ - int i; - static int file_opened = 0; - static int current_file_offset = 0; - - switch (vector) { - case 0x0: /* reset() */ - /* TODO */ - cpu->machine->exit_without_entering_debugger = 1; - cpu->running = 0; - break; - case 0x10: /* restart() */ - /* TODO */ - cpu->machine->exit_without_entering_debugger = 1; - cpu->running = 0; - break; - case 0x18: /* reinit() */ - /* TODO */ - cpu->machine->exit_without_entering_debugger = 1; - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x30: /* open() */ - /* - * TODO: This is just a hack to allow Sprite/pmax' bootblock - * code to load /vmsprite. The filename argument (in A0) - * is ignored, and a file handle value of 1 is returned. - */ - if (file_opened) { - fatal("\ndec_jumptable_func(): opening more than one " - "file isn't supported yet.\n"); - cpu->running = 0; - } - file_opened = 1; - cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; - break; - case 0x38: /* read(handle, ptr, length) */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = (uint64_t) -1; - if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) { - int disk_id = diskimage_bootdev(cpu->machine, NULL); - int res; - unsigned char *tmp_buf; - - CHECK_ALLOCATION(tmp_buf = (unsigned char *) - malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); - - res = diskimage_access(cpu->machine, disk_id, - DISKIMAGE_SCSI, 0, current_file_offset, tmp_buf, - cpu->cd.mips.gpr[MIPS_GPR_A2]); - - /* If the transfer was successful, transfer the data - to emulated memory: */ - if (res) { - uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; - store_buf(cpu, dst, (char *)tmp_buf, - cpu->cd.mips.gpr[MIPS_GPR_A2]); - cpu->cd.mips.gpr[MIPS_GPR_V0] = - cpu->cd.mips.gpr[MIPS_GPR_A2]; - current_file_offset += - cpu->cd.mips.gpr[MIPS_GPR_A2]; - } - - free(tmp_buf); - } - break; - case 0x58: /* lseek(handle, offset[, whence]) */ - /* TODO */ - if (cpu->cd.mips.gpr[MIPS_GPR_A2] == 0) - current_file_offset = cpu->cd.mips.gpr[MIPS_GPR_A1]; - else - fatal("WARNING! Unimplemented whence in " - "dec_jumptable_func()\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x68: /* putchar() */ - console_putchar(cpu->machine->main_console_handle, - cpu->cd.mips.gpr[MIPS_GPR_A0]); - break; - case 0x88: /* printf() */ - return 0x30; - case 0x108: /* getenv2() */ - return 0x64; - default: - cpu_register_dump(cpu->machine, cpu, 1, 0x1); - printf("a0 points to: "); - for (i=0; i<40; i++) { - unsigned char ch = '\0'; - cpu->memory_rw(cpu, cpu->mem, - (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch, - sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); - if (ch >= ' ' && ch < 126) - printf("%c", ch); - else - printf("[%02x]", ch); - } - printf("\n"); - fatal("PROM emulation: unimplemented JUMP TABLE vector " - "0x%x (decimal function %i)\n", vector, vector/8); - cpu->running = 0; - } - - return 0; -} - - -/* - * decstation_prom_emul(): - * - * DECstation PROM emulation. - * - * Callback functions: - * 0x0c strcmp() - * 0x14 strlen() - * 0x24 getchar() - * 0x28 gets() - * 0x2c puts() - * 0x30 printf() - * 0x38 iopoll() - * 0x54 bootinit() - * 0x58 bootread() - * 0x64 getenv() - * 0x6c slot_address() - * 0x70 wbflush() - * 0x7c clear_cache() - * 0x80 getsysid() - * 0x84 getbitmap() - * 0x88 disableintr() - * 0x8c enableintr() - * 0x9c halt() - * 0xa4 gettcinfo() - * 0xa8 execute_cmd() - * 0xac rex() - */ -int decstation_prom_emul(struct cpu *cpu) -{ - int i, j, ch, argreg, argdata; - int vector = cpu->pc & 0xfff; - int callback = (cpu->pc & 0xf000)? 1 : 0; - unsigned char buf[100]; - unsigned char ch1, ch2, ch3; - uint64_t tmpaddr, slot_base = 0x10000000, slot_size = 0; - - if (!callback) { - vector = dec_jumptable_func(cpu, vector); - if (vector == 0) - return 1; - } else { - /* Vector number is n*4, PC points to n*8. */ - vector /= 2; - } - - switch (vector) { - case 0x0c: /* strcmp(): */ - i = j = 0; - do { - ch1 = mem_readchar(cpu, MIPS_GPR_A0, i++); - ch2 = mem_readchar(cpu, MIPS_GPR_A1, j++); - } while (ch1 == ch2 && ch1 != '\0'); - - /* If ch1=='\0', then strings are equal. */ - if (ch1 == '\0') - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - if ((signed char)ch1 > (signed char)ch2) - cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; - if ((signed char)ch1 < (signed char)ch2) - cpu->cd.mips.gpr[MIPS_GPR_V0] = (uint64_t) -1; - break; - case 0x14: /* strlen(): */ - i = 0; - do { - ch2 = mem_readchar(cpu, MIPS_GPR_A0, i++); - } while (ch2 != 0); - cpu->cd.mips.gpr[MIPS_GPR_V0] = i - 1; - break; - case 0x24: /* getchar() */ - /* debug("[ DEC PROM getchar() ]\n"); */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar( - cpu->machine->main_console_handle); - break; - case 0x28: /* gets() */ - /* debug("[ DEC PROM gets() ]\n"); */ - tmpaddr = cpu->cd.mips.gpr[MIPS_GPR_A0]; - i = 0; - - /* TODO: Make this not hang (block) the entire emulator */ - - do { - while ((ch = console_readchar( - cpu->machine->main_console_handle)) < 1) - ; - if (ch == '\r') - ch = '\n'; - ch2 = ch; - - if (ch == '\b') { - if (i > 0) { - console_putchar(cpu->machine-> - main_console_handle, ch2); - console_putchar(cpu->machine-> - main_console_handle, ' '); - console_putchar(cpu->machine-> - main_console_handle, ch2); - } - } else - console_putchar(cpu->machine-> - main_console_handle, ch2); - - fflush(stdout); - - if (ch == '\n') { - /* It seems that trailing newlines - are not included in the buffer. */ - } else if (ch != '\b') { - cpu->memory_rw(cpu, cpu->mem, (int32_t) - cpu->cd.mips.gpr[MIPS_GPR_A0] + i, - &ch2, sizeof(ch2), MEM_WRITE, - CACHE_DATA | NO_EXCEPTIONS); - i++; - } else { - if (i > 0) - i--; - } - } while (ch2 != '\n'); - - /* Trailing nul-byte: */ - ch2 = '\0'; - cpu->memory_rw(cpu, cpu->mem, (int32_t) - cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &ch2, sizeof(ch2), - MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS); - - /* Return the input argument: */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = cpu->cd.mips.gpr[MIPS_GPR_A0]; - break; - case 0x2c: /* puts() */ - i = 0; - while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0') - console_putchar(cpu->machine->main_console_handle, ch); - console_putchar(cpu->machine->main_console_handle, '\n'); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x30: /* printf() */ - if (cpu->machine->register_dump || - cpu->machine->instruction_trace) - debug("PROM printf(0x%08lx): \n", - (long)cpu->cd.mips.gpr[MIPS_GPR_A0]); - - i = 0; ch = -1; argreg = MIPS_GPR_A1; - while (ch != '\0') { - char printfbuf[8000]; - size_t x; - - printfbuf[0] = printfbuf[sizeof(printfbuf)-1] = '\0'; - - ch = mem_readchar(cpu, MIPS_GPR_A0, i++); - switch (ch) { - case '%': - ch = '0'; - while (ch >= '0' && ch <= '9') - ch = mem_readchar(cpu, - MIPS_GPR_A0, i++); - - switch (ch) { - case '%': - strlcpy(printfbuf, "%%", - sizeof(printfbuf)); - break; - case 'c': - case 'd': - case 's': - case 'x': - /* Get argument: */ - if (argreg > MIPS_GPR_A3) { -#if 1 - /* Linux booters seem to go - over the edge sometimes: */ - ch = '\0'; - strlcpy(printfbuf, "[...]\n", - sizeof(printfbuf)); -#else - printf("[ decstation_prom_emul" - "(): too many arguments ]"); - /* This reuses the last arg, - which is utterly incorrect. - (TODO) */ - argreg = MIPS_GPR_A3; -#endif - } - - ch2 = argdata = - cpu->cd.mips.gpr[argreg]; - - switch (ch) { - case 'c': - snprintf(printfbuf, sizeof( - printfbuf), "%c", ch2); - break; - case 'd': - snprintf(printfbuf, sizeof( - printfbuf), "%d", argdata); - break; - case 'x': - snprintf(printfbuf, sizeof( - printfbuf), "%x", argdata); - break; - case 's': - /* Print a "%s" string. */ - j = 0; ch3 = '\n'; - while (ch2) { - ch2 = mem_readchar(cpu, - argreg, j++); - if (ch2) { - snprintf( - printfbuf + - strlen( - printfbuf), - sizeof( - printfbuf)- - 1-strlen( - printfbuf), - "%c", ch2); - ch3 = ch2; - } - } - break; - } - argreg ++; - break; - default: - printf("[ unknown printf format char" - " '%c' ]", ch); - } - break; - case '\0': - break; - default: - snprintf(printfbuf, sizeof(printfbuf), - "%c", ch); - } - - printfbuf[sizeof(printfbuf)-1] = '\0'; - - for (x=0; xmachine-> - main_console_handle, printfbuf[x]); - } - if (cpu->machine->register_dump || - cpu->machine->instruction_trace) - debug("\n"); - fflush(stdout); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x54: /* bootinit() */ - /* debug("[ DEC PROM bootinit(0x%08x): TODO ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x58: /* bootread(int b, void *buffer, int n) */ - /* - * Read data from the boot device. - * b is a sector number (512 bytes per sector), - * buffer is the destination address, and n - * is the number of _bytes_ to read. - * - * TODO: Return value? NetBSD thinks that 0 is ok. - */ - debug("[ DEC PROM bootread(0x%x, 0x%08x, 0x%x) ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0], - (int)cpu->cd.mips.gpr[MIPS_GPR_A1], - (int)cpu->cd.mips.gpr[MIPS_GPR_A2]); - - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - - if ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2] > 0) { - int disk_id = diskimage_bootdev(cpu->machine, NULL); - int res; - unsigned char *tmp_buf; - - CHECK_ALLOCATION(tmp_buf = (unsigned char *) - malloc(cpu->cd.mips.gpr[MIPS_GPR_A2])); - - res = diskimage_access(cpu->machine, disk_id, - DISKIMAGE_SCSI, 0, - cpu->cd.mips.gpr[MIPS_GPR_A0] * 512, tmp_buf, - cpu->cd.mips.gpr[MIPS_GPR_A2]); - - /* If the transfer was successful, transfer the data - to emulated memory: */ - if (res) { - uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; - if (dst < 0x80000000ULL) - dst |= 0x80000000; - - store_buf(cpu, dst, (char *)tmp_buf, - cpu->cd.mips.gpr[MIPS_GPR_A2]); - cpu->cd.mips.gpr[MIPS_GPR_V0] = - cpu->cd.mips.gpr[MIPS_GPR_A2]; - } - - free(tmp_buf); - } - break; - case 0x64: /* getenv() */ - /* Find the environment variable given by a0: */ - for (i=0; i<(int)sizeof(buf); i++) - cpu->memory_rw(cpu, cpu->mem, (int32_t) - cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &buf[i], - sizeof(char), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); - buf[sizeof(buf)-1] = '\0'; - debug("[ DEC PROM getenv(\"%s\") ]\n", buf); - for (i=0; i<0x1000; i++) { - /* Matching string at offset i? */ - int nmatches = 0; - for (j=0; j<(int32_t)strlen((char *)buf); j++) { - cpu->memory_rw(cpu, cpu->mem, (int32_t) - (DEC_PROM_STRINGS + i + j), &ch2, - sizeof(char), MEM_READ, CACHE_DATA | - NO_EXCEPTIONS); - if (ch2 == buf[j]) - nmatches++; - } - cpu->memory_rw(cpu, cpu->mem, (int32_t)(DEC_PROM_STRINGS - + i + strlen((char *)buf)), &ch2, sizeof(char), - MEM_READ, CACHE_DATA | NO_EXCEPTIONS); - if (nmatches == (int)strlen((char *)buf) && ch2=='=') { - cpu->cd.mips.gpr[MIPS_GPR_V0] = - DEC_PROM_STRINGS + i + - strlen((char *)buf) + 1; - return 1; - } - } - /* Return NULL if string wasn't found. */ - fatal("[ DEC PROM getenv(\"%s\"): WARNING: Not in " - "environment! ]\n", buf); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x6c: /* ulong slot_address(int sn) */ - debug("[ DEC PROM slot_address(%i) ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - /* TODO: This is too hardcoded. */ - /* TODO 2: Should these be physical or virtual addresses? */ - switch (cpu->machine->machine_subtype) { - case MACHINE_DEC_3MAX_5000: - slot_base = KN02_PHYS_TC_0_START;/* 0x1e000000 */ - slot_size = 4*1048576; /* 4 MB */ - break; - case MACHINE_DEC_3MIN_5000: - slot_base = 0x10000000; - slot_size = 0x4000000; /* 64 MB */ - break; - case MACHINE_DEC_3MAXPLUS_5000: - slot_base = 0x1e000000; - slot_size = 0x800000; /* 8 MB */ - break; - case MACHINE_DEC_MAXINE_5000: - slot_base = 0x10000000; - slot_size = 0x4000000; /* 64 MB */ - break; - default: - fatal("warning: DEC PROM slot_address() " - "unimplemented for this machine type\n"); - } - cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t) - (0x80000000 + slot_base + slot_size * - cpu->cd.mips.gpr[MIPS_GPR_A0]); - break; - case 0x70: /* wbflush() */ - debug("[ DEC PROM wbflush(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x7c: /* clear_cache(addr, len) */ - debug("[ DEC PROM clear_cache(0x%x,%i) ]\n", - (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0], - (int)cpu->cd.mips.gpr[MIPS_GPR_A1]); - /* TODO */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* ? */ - break; - case 0x80: /* getsysid() */ - /* debug("[ DEC PROM getsysid() ]\n"); */ - /* TODO: why did I add the 0x82 stuff??? */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = ((uint32_t)0x82 << 24) - + (cpu->machine->machine_subtype << 16) + (0x3 << 8); - cpu->cd.mips.gpr[MIPS_GPR_V0] = - (int64_t)(int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0]; - break; - case 0x84: /* getbitmap() */ - debug("[ DEC PROM getbitmap(0x%08x) ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - store_buf(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0], - (char *)cpu->machine->md.pmax->memmap, - sizeof(struct dec_memmap)); - cpu->cd.mips.gpr[MIPS_GPR_V0] = - sizeof(cpu->machine->md.pmax->memmap->bitmap); - break; - case 0x88: /* disableintr() */ - debug("[ DEC PROM disableintr(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x8c: /* enableintr() */ - debug("[ DEC PROM enableintr(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0x9c: /* halt() */ - debug("[ DEC PROM halt() ]\n"); - cpu->machine->exit_without_entering_debugger = 1; - cpu->running = 0; - break; - case 0xa4: /* gettcinfo() */ - /* - * These are just bogus values... TODO - * - * 0: revision - * 4: clock period in nano seconds - * 8: slot size in megabytes TODO: not same for all models! - * 12: I/O timeout in cycles - * 16: DMA address range in megabytes - * 20: maximum DMA burst length - * 24: turbochannel parity (yes = 1) - * 28: reserved - */ - store_32bit_word(cpu, DEC_PROM_TCINFO + 0, 0); - store_32bit_word(cpu, DEC_PROM_TCINFO + 4, 50); - store_32bit_word(cpu, DEC_PROM_TCINFO + 8, 4); - store_32bit_word(cpu, DEC_PROM_TCINFO + 12, 10); - store_32bit_word(cpu, DEC_PROM_TCINFO + 16, 1); - store_32bit_word(cpu, DEC_PROM_TCINFO + 20, 100); - store_32bit_word(cpu, DEC_PROM_TCINFO + 24, 0); - store_32bit_word(cpu, DEC_PROM_TCINFO + 28, 0); - cpu->cd.mips.gpr[MIPS_GPR_V0] = DEC_PROM_TCINFO; - break; - case 0xa8: /* int execute_cmd(char *) */ - i = 0; - while ((ch = mem_readchar(cpu, MIPS_GPR_A0, i++)) != '\0') - console_putchar(cpu->machine->main_console_handle, ch); - console_putchar(cpu->machine->main_console_handle, '\n'); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 0xac: /* rex() */ - debug("[ DEC PROM rex('%c') ]\n", - (int)cpu->cd.mips.gpr[MIPS_GPR_A0]); - switch ((int32_t)cpu->cd.mips.gpr[MIPS_GPR_A0]) { - case 'h': - debug("DEC PROM: rex('h') ==> halt\n"); - cpu->machine->exit_without_entering_debugger = 1; - cpu->running = 0; - break; - case 'b': - debug("DEC PROM: rex('b') ==> reboot: TODO " - "(halting CPU instead)\n"); - cpu->machine->exit_without_entering_debugger = 1; - cpu->running = 0; - break; - default: - fatal("DEC prom emulation: unknown rex() a0=0x%" PRIx64 - " ('%c')\n", - (int64_t) cpu->cd.mips.gpr[MIPS_GPR_A0], - (char) cpu->cd.mips.gpr[MIPS_GPR_A0]); - cpu->running = 0; - } - break; - default: - cpu_register_dump(cpu->machine, cpu, 1, 0x1); - printf("a0 points to: "); - for (i=0; i<40; i++) { - unsigned char chTmp = '\0'; - cpu->memory_rw(cpu, cpu->mem, (int32_t) - cpu->cd.mips.gpr[MIPS_GPR_A0] + i, &chTmp, - sizeof(chTmp), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); - if (chTmp >= ' ' && chTmp < 126) - printf("%c", chTmp); - else - printf("[%02x]", chTmp); - } - printf("\n"); - fatal("PROM emulation: unimplemented callback vector 0x%x\n", - vector); - cpu->running = 0; - } - - return 1; -} - diff -Nru gxemul-0.6.2/src/promemul/dreamcast.c gxemul-0.7.0+dfsg/src/promemul/dreamcast.c --- gxemul-0.6.2/src/promemul/dreamcast.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/dreamcast.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2006-2021 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: Dreamcast PROM emulation + * + * NOTE: This module probably only emulates enough system/BIOS calls to let + * NetBSD/dreamcast, Linux/dreamcast, and various KOS demos run. Don't expect + * it do be fully functional. + * + * Dreamcast memory layout during startup: + * + * 0xa0000000: 2 MB ROM/BIOS. This is copied into RAM (0x8c000000) during + * bootup by the real BIOS. In GXemul's fake PROM implementation, + * the only thing present at 0xa0000000 is an opcode which + * triggers a reboot/shutdown of the emulator. + * + * 0x8c000000 - 0x8c0000ff: Various variables and vectors. + * pointer (32-bit word) at 0x8c0000b0: SYSINFO + * pointer (32-bit word) at 0x8c0000b4: ROMFONT + * pointer (32-bit word) at 0x8c0000b8: FLASHROM + * pointer (32-bit word) at 0x8c0000bc: GDROM + * pointer (32-bit word) at 0x8c0000c0: (?) something + * pointer (32-bit word) at 0x8c0000e0: "main menu" call, or "continue + * booting" (?) or something. + * + * 0x8c000100: Not on a real Dreamcast, but in GXemul: This area is filled with + * a special invalid instruction. Each instruction slot corresponds + * to one of the pointers above (SYSINFO, ROMFONT, etc). + * + * 0x8c008000: This is where the first 32KB of the data track of a CDROM + * gets loaded, also known as the "IP.BIN" part. + * + * 0x8c010000: This is where the first binary executable gets loaded. The name + * of the executable is given in IP.BIN, and refers to the ISO9660 + * filename on the CDROM. A common file name is "1ST_READ.BIN". + * + * See http://mc.pp.se/dc/syscalls.html for a description of what the + * PROM syscalls do. The symbolic names in this module are the same as on + * that page. + */ + +#include +#include +#include +#include + +#include "cpu.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" +#include "thirdparty/dreamcast_pvr.h" + +/* The ROM FONT seems to be located just after 1MB, in a real Dreamcast: */ +#define DREAMCAST_ROMFONT_BASE 0x80100020 +extern unsigned char font8x16[]; + +/* Where the machine ID (64-bit) is stored. */ +#define DREAMCAST_MACHINE_ID_ADDRESS 0x80000068 + + +static int booting_from_cdrom = 0; + + +/* + * dreamcast_romfont_init() + * + * Initialize the ROM font. + */ +static void dreamcast_romfont_init(struct machine *machine) +{ + struct cpu *cpu = machine->cpus[0]; + int i, y, v; + uint64_t d = DREAMCAST_ROMFONT_BASE; + + /* + * 288 narrow glyphs (12 x 24 pixels): + * + * Glyphs 1-94 are ASCII characters 33-126, according to + * http://mc.pp.se/dc/syscalls.html#vecB4 + * + * syscalls.html says "(As there is no glyph for ASCII space, use + * glyph 96 = ISO-8859-1 unbreakable space instead.)", but this does + * not seem to work. Marcus Comstedt's own example (video.s) uses + * char 288 for space instead (but the comment says char 72). + * + * TODO: A better looking font. This simply reuses the standard 8x16 + * font, which looks odd in Dreamcast programs. + */ + for (i=0; i<288; i++) { + for (y=0; y<24; y+=2) { + if (y <= 1 || y >= 22) + v = 0; + else + v = random(); + store_byte(cpu, d++, v & 0x3f); + store_byte(cpu, d++, v & 0xc3); + store_byte(cpu, d++, v & 0xfc); + } + } + + for (i=1; i<=94; i++) { + d = DREAMCAST_ROMFONT_BASE + i * (24 * 3 / 2); + int c = 32 + i; + int u; + for (y=0; y<24; y+=2) { + if (y < 4 || y >= 20) + u = v = 0x00; + else + u = font8x16[c*16 + (y-4)], v = font8x16[c*16 + (y-4+1)]; + + // 00 00 u7 u6 u5 u4 u3 u2 u1 u0 00 00 + // 00 00 v7 v6 v5 v4 v3 v2 v1 v0 00 00 + // becomes: + // first byte: 00 00 u7 u6 u5 u4 u3 u2 + // second byte: u1 u0 00 00 00 00 v7 v6 + // third byte: v5 v4 v3 v2 v1 v0 00 00 + store_byte(cpu, d++, u >> 2); + store_byte(cpu, d++, (u << 6) | (v >> 6)); + store_byte(cpu, d++, v << 2); + } + } + + // "ISO-8859-1 characters 160-255" (at pos 96..191): + for (i=96; i<=191; i++) { + d = DREAMCAST_ROMFONT_BASE + i * (24 * 3 / 2); + int c = i - 96 + 160; + int u; + for (y=0; y<24; y+=2) { + if (y < 4 || y >= 20) + u = v = 0; + else + u = font8x16[c*16 + (y-4)], v = font8x16[c*16 + (y-4+1)]; + + store_byte(cpu, d++, u >> 2); + store_byte(cpu, d++, (u << 6) | (v >> 6)); + store_byte(cpu, d++, v << 2); + } + } + + d = DREAMCAST_ROMFONT_BASE + 289 * (24 * 3 / 2); + + /* 7078 wide glyphs (24 x 24 pixels): */ + for (i=1; i<7078; i++) { + for (y=0; y<24; y++) { + if (y <= 1 || y >= 22) + v = 0; + else + v = 0xff; + store_byte(cpu, d++, v & 0x3f); + store_byte(cpu, d++, v); + store_byte(cpu, d++, v & 0xfc); + } + } + + /* 129 VME icons (32 x 32 pixels): */ + for (i=0; i<129; i++) { + for (y=0; y<32; y++) { + if (y <= 1 || y >= 30) + v = 0; + else + v = random(); + store_byte(cpu, d++, v & 0x3f); + store_byte(cpu, d++, v); + store_byte(cpu, d++, v); + store_byte(cpu, d++, v & 0xfc); + } + } +} + + +/* + * dreamcast_machine_setup(): + * + * Initializes pointers to Dreamcast PROM syscalls. + */ +void dreamcast_machine_setup(struct machine *machine) +{ + int i; + struct cpu *cpu = machine->cpus[0]; + + for (i=0; i<0x50; i+=sizeof(uint32_t)) { + /* Store pointer to PROM routine... */ + store_32bit_word(cpu, 0x8c0000b0 + i, 0x8c000100 + i); + + /* ... which contains only 1 instruction, a special + opcode which triggers PROM emulation: */ + store_16bit_word(cpu, 0x8c000100 + i, SH_INVALID_INSTR); + } + + /* PROM reboot, in case someone jumps to 0xa0000000: */ + store_16bit_word(cpu, 0xa0000000, SH_INVALID_INSTR); + + /* Machine ID (64-bit): */ + store_64bit_word(cpu, DREAMCAST_MACHINE_ID_ADDRESS, 0x0000000000000000ULL); + + dreamcast_romfont_init(machine); + + /* Return address, if the user program returns: exit. */ + cpu->cd.sh.pr = 0x8c0000e0 + (0x100 - 0xb0); + + /* Stack starting at end of RAM. */ + cpu->cd.sh.r[15] = 0x8c000000 + 16 * 1048576; +} + + +/* + * dreamcast_emul(): + * + * We end up here if someone branched or called to 0x8c000100 + ofs, + * where ofs is a small number. These addresses correspond to the code reading + * a pointer from 0x8c0000b0 + ofs and calling it. + * + * See http://mc.pp.se/dc/syscalls.html for more details. + */ +void dreamcast_emul(struct cpu *cpu) +{ + // cpu->pc is the address where PROM emulation was triggered, but + // what we are after is the indirect vector that was used to fetch + // that address. + uint32_t vectorAddr = ((cpu->pc & 0x00ffffff) - 0x100 + 0xb0) | 0x8c000000; + + int r1 = cpu->cd.sh.r[1]; + int r6 = cpu->cd.sh.r[6]; + int r7 = cpu->cd.sh.r[7]; + + /* Special case: Reboot */ + if ((uint32_t)cpu->pc == 0x80000000 || (uint32_t)cpu->pc == 0xa0000000) { + debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_WARNING, "rebooting"); + cpu->running = 0; + return; + } + + switch (vectorAddr) { + + case 0x8c0000b0: + /* SYSINFO */ + switch (r7) { + case 0: /* SYSINFO_INIT: Ignored for now. */ + debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_INFO, "SYSINFO_INIT: ignored for now"); + break; + case 3: /* SYSINFO_ID: */ + cpu->cd.sh.r[0] = (uint32_t)DREAMCAST_MACHINE_ID_ADDRESS; + break; + default:debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_ERROR, "SYSINFO: Unimplemented r7=%i", r7); + goto bad; + } + break; + + case 0x8c0000b4: + /* ROMFONT */ + switch (r1) { + case 0: /* ROMFONT_ADDRESS */ + cpu->cd.sh.r[0] = DREAMCAST_ROMFONT_BASE; + break; + default:debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_ERROR, "ROMFONT: Unimplemented r1=%i", r1); + goto bad; + } + break; + + case 0x8c0000b8: + /* FLASHROM */ + switch (r7) { + case 0: /* FLASHROM_INFO */ + /* TODO */ + cpu->cd.sh.r[0] = (uint32_t) -1; + break; + case 1: /* FLASHROM_READ */ + /* TODO */ + cpu->cd.sh.r[0] = (uint32_t) -1; + break; + default:debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_ERROR, "FLASHROM: Unimplemented r7=%i", r7); + goto bad; + } + break; + + case 0x8c0000bc: + switch ((int32_t)r6) { + case 0: /* GD-ROM emulation */ + switch (r7) { + case 0: /* GDROM_SEND_COMMAND */ + /* TODO */ + cpu->cd.sh.r[0] = (uint32_t) -1; + break; + case 1: /* GDROM_CHECK_COMMAND */ + /* TODO */ + cpu->cd.sh.r[0] = 0; + break; + case 2: /* GDROM_MAINLOOP */ + /* TODO */ + break; + case 3: /* GDROM_INIT */ + /* TODO: Do something here? */ + break; + case 4: /* GDROM_CHECK_DRIVE */ + /* TODO: Return status words */ + break; + default:debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_ERROR, "GDROM: Unimplemented r7=%i", r7); + goto bad; + } + break; + default:debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_ERROR, "0xbc: Unimplemented r6=%i", r6); + goto bad; + } + break; + + case 0x8c0000e0: + /* + * This seems to have two uses: + * + * 1. KallistiOS calls this from arch_menu(), i.e. to return + * from a running program. + * 2. The "licence code" in the IP.BIN code when booting from + * a bootable CD image calls this once the license screen + * has been displayed, and it wants the ROM to jump to + * 0x8c00b800 ("Bootstrap 1"). + * + * The easiest way to support both is probably to keep track + * of whether the IP.BIN code was started by the (software) + * ROM emulation code, or not. + */ + if (booting_from_cdrom) { + debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_INFO, "Switching to bootstrap 1"); + + booting_from_cdrom = 0; + + // Jump to bootstrap 1 + cpu->pc = 0x8c00b800; + return; + } else { + debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_WARNING, "Returning to main menu."); + cpu->running = 0; + } + break; + + case 0x8c0000f0: + /* + * GXemul hack: + * + * The vector (word) at 0x8c0000f0 contains the value 0x8c000140. + * + * By jumping to this address (0x8c000140), a "boot from + * CDROM" is simulated. Control is transfered to the license + * code in the loaded IP.BIN file. + */ + debugmsg(SUBSYS_PROMEMUL, "dreamcast", VERBOSITY_INFO, "boot from CDROM"); + booting_from_cdrom = 1; + cpu->pc = 0x8c008300; + return; + + default:goto bad; + } + + /* Return from subroutine: */ + cpu->pc = cpu->cd.sh.pr; + + return; + +bad: + cpu_register_dump(cpu->machine, cpu, 1, 0); + printf("\n"); + fatal("[ dreamcast_emul(): unimplemented dreamcast PROM call, " + "pc=0x%08" PRIx32" (vectorAddr=0x%08" PRIx32") ]\n", (uint32_t)cpu->pc, vectorAddr); + cpu->running = 0; + return; +} + diff -Nru gxemul-0.6.2/src/promemul/dreamcast.cc gxemul-0.7.0+dfsg/src/promemul/dreamcast.cc --- gxemul-0.6.2/src/promemul/dreamcast.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/dreamcast.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2006-2014 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: Dreamcast PROM emulation - * - * NOTE: This module probably only emulates enough system/BIOS calls to let - * NetBSD/dreamcast, Linux/dreamcast, and various KOS demos run. Don't expect - * it do be fully functional. - * - * Dreamcast memory layout during startup: - * - * 0xa0000000: 2 MB ROM/BIOS. This is copied into RAM (0x8c000000) during - * bootup by the real BIOS. In GXemul's fake PROM implementation, - * the only thing present at 0xa0000000 is an opcode which - * triggers a reboot/shutdown of the emulator. - * - * 0x8c000000 - 0x8c0000ff: Various variables and vectors. - * pointer (32-bit word) at 0x8c0000b0: SYSINFO - * pointer (32-bit word) at 0x8c0000b4: ROMFONT - * pointer (32-bit word) at 0x8c0000b8: FLASHROM - * pointer (32-bit word) at 0x8c0000bc: GDROM - * pointer (32-bit word) at 0x8c0000c0: (?) something - * pointer (32-bit word) at 0x8c0000e0: "main menu" call, or "continue - * booting" (?) or something. - * - * 0x8c000100: Not on a real Dreamcast, but in GXemul: This area is filled with - * a special invalid instruction. Each instruction slot corresponds - * to one of the pointers above (SYSINFO, ROMFONT, etc). - * - * 0x8c008000: This is where the first 32KB of the data track of a CDROM - * gets loaded, also known as the "IP.BIN" part. - * - * 0x8c010000: This is where the first binary executable gets loaded. The name - * of the executable is given in IP.BIN, and refers to the ISO9660 - * filename on the CDROM. A common file name is "1ST_READ.BIN". - * - * See http://mc.pp.se/dc/syscalls.html for a description of what the - * PROM syscalls do. The symbolic names in this module are the same as on - * that page. - */ - -#include -#include -#include -#include - -#include "cpu.h" -#include "machine.h" -#include "memory.h" -#include "misc.h" -#include "thirdparty/dreamcast_pvr.h" - -/* The ROM FONT seems to be located just after 1MB, in a real Dreamcast: */ -#define DREAMCAST_ROMFONT_BASE 0x80100020 -extern unsigned char font8x16[]; - -/* Where the machine ID (64-bit) is stored. */ -#define DREAMCAST_MACHINE_ID_ADDRESS 0x80000068 - - -static int booting_from_cdrom = 0; - - -/* - * dreamcast_romfont_init() - * - * Initialize the ROM font. - */ -static void dreamcast_romfont_init(struct machine *machine) -{ - struct cpu *cpu = machine->cpus[0]; - int i, y, v; - uint64_t d = DREAMCAST_ROMFONT_BASE; - - /* - * 288 narrow glyphs (12 x 24 pixels): - * - * Glyphs 1-94 are ASCII characters 33-126, according to - * http://mc.pp.se/dc/syscalls.html#vecB4 - * - * syscalls.html says "(As there is no glyph for ASCII space, use - * glyph 96 = ISO-8859-1 unbreakable space instead.)", but this does - * not seem to work. Marcus Comstedt's own example (video.s) uses - * char 288 for space instead (but the comment says char 72). - * - * TODO: A better looking font. This simply reuses the standard 8x16 - * font, which looks odd in Dreamcast programs. - */ - for (i=0; i<288; i++) { - for (y=0; y<24; y+=2) { - if (y <= 1 || y >= 22) - v = 0; - else - v = random(); - store_byte(cpu, d++, v & 0x3f); - store_byte(cpu, d++, v & 0xc3); - store_byte(cpu, d++, v & 0xfc); - } - } - - for (i=1; i<=94; i++) { - d = DREAMCAST_ROMFONT_BASE + i * (24 * 3 / 2); - int c = 32 + i; - int u; - for (y=0; y<24; y+=2) { - if (y < 4 || y >= 20) - u = v = 0x00; - else - u = font8x16[c*16 + (y-4)], v = font8x16[c*16 + (y-4+1)]; - - // 00 00 u7 u6 u5 u4 u3 u2 u1 u0 00 00 - // 00 00 v7 v6 v5 v4 v3 v2 v1 v0 00 00 - // becomes: - // first byte: 00 00 u7 u6 u5 u4 u3 u2 - // second byte: u1 u0 00 00 00 00 v7 v6 - // third byte: v5 v4 v3 v2 v1 v0 00 00 - store_byte(cpu, d++, u >> 2); - store_byte(cpu, d++, (u << 6) | (v >> 6)); - store_byte(cpu, d++, v << 2); - } - } - - // "ISO-8859-1 characters 160-255" (at pos 96..191): - for (i=96; i<=191; i++) { - d = DREAMCAST_ROMFONT_BASE + i * (24 * 3 / 2); - int c = i - 96 + 160; - int u; - for (y=0; y<24; y+=2) { - if (y < 4 || y >= 20) - u = v = 0; - else - u = font8x16[c*16 + (y-4)], v = font8x16[c*16 + (y-4+1)]; - - store_byte(cpu, d++, u >> 2); - store_byte(cpu, d++, (u << 6) | (v >> 6)); - store_byte(cpu, d++, v << 2); - } - } - - d = DREAMCAST_ROMFONT_BASE + 289 * (24 * 3 / 2); - - /* 7078 wide glyphs (24 x 24 pixels): */ - for (i=1; i<7078; i++) { - for (y=0; y<24; y++) { - if (y <= 1 || y >= 22) - v = 0; - else - v = 0xff; - store_byte(cpu, d++, v & 0x3f); - store_byte(cpu, d++, v); - store_byte(cpu, d++, v & 0xfc); - } - } - - /* 129 VME icons (32 x 32 pixels): */ - for (i=0; i<129; i++) { - for (y=0; y<32; y++) { - if (y <= 1 || y >= 30) - v = 0; - else - v = random(); - store_byte(cpu, d++, v & 0x3f); - store_byte(cpu, d++, v); - store_byte(cpu, d++, v); - store_byte(cpu, d++, v & 0xfc); - } - } -} - - -/* - * dreamcast_machine_setup(): - * - * Initializes pointers to Dreamcast PROM syscalls. - */ -void dreamcast_machine_setup(struct machine *machine) -{ - int i; - struct cpu *cpu = machine->cpus[0]; - - for (i=0; i<0x50; i+=sizeof(uint32_t)) { - /* Store pointer to PROM routine... */ - store_32bit_word(cpu, 0x8c0000b0 + i, 0x8c000100 + i); - - /* ... which contains only 1 instruction, a special - opcode which triggers PROM emulation: */ - store_16bit_word(cpu, 0x8c000100 + i, SH_INVALID_INSTR); - } - - /* PROM reboot, in case someone jumps to 0xa0000000: */ - store_16bit_word(cpu, 0xa0000000, SH_INVALID_INSTR); - - /* Machine ID (64-bit): */ - store_64bit_word(cpu, DREAMCAST_MACHINE_ID_ADDRESS, 0x0000000000000000ULL); - - dreamcast_romfont_init(machine); - - /* Return address, if the user program returns: exit. */ - cpu->cd.sh.pr = 0x8c0000e0 + (0x100 - 0xb0); - - /* Stack starting at end of RAM. */ - cpu->cd.sh.r[15] = 0x8c000000 + 16 * 1048576; -} - - -/* - * dreamcast_emul(): - * - * We end up here if someone branched or called to 0x8c000100 + ofs, - * where ofs is a small number. These addresses correspond to the code reading - * a pointer from 0x8c0000b0 + ofs and calling it. - * - * See http://mc.pp.se/dc/syscalls.html for more details. - */ -void dreamcast_emul(struct cpu *cpu) -{ - // cpu->pc is the address where PROM emulation was triggered, but - // what we are after is the indirect vector that was used to fetch - // that address. - uint32_t vectorAddr = ((cpu->pc & 0x00ffffff) - 0x100 + 0xb0) | 0x8c000000; - - int r1 = cpu->cd.sh.r[1]; - int r6 = cpu->cd.sh.r[6]; - int r7 = cpu->cd.sh.r[7]; - - /* Special case: Reboot */ - if ((uint32_t)cpu->pc == 0x80000000 || (uint32_t)cpu->pc == 0xa0000000) { - fatal("[ dreamcast reboot ]\n"); - cpu->running = 0; - return; - } - - switch (vectorAddr) { - - case 0x8c0000b0: - /* SYSINFO */ - switch (r7) { - case 0: /* SYSINFO_INIT: Ignored for now. */ - break; - case 3: /* SYSINFO_ID: */ - cpu->cd.sh.r[0] = (uint32_t)DREAMCAST_MACHINE_ID_ADDRESS; - break; - default:fatal("[ SYSINFO: Unimplemented r7=%i ]\n", r7); - goto bad; - } - break; - - case 0x8c0000b4: - /* ROMFONT */ - switch (r1) { - case 0: /* ROMFONT_ADDRESS */ - cpu->cd.sh.r[0] = DREAMCAST_ROMFONT_BASE; - break; - default:fatal("[ ROMFONT: Unimplemented r1=%i ]\n", r1); - goto bad; - } - break; - - case 0x8c0000b8: - /* FLASHROM */ - switch (r7) { - case 0: /* FLASHROM_INFO */ - /* TODO */ - cpu->cd.sh.r[0] = (uint32_t) -1; - break; - case 1: /* FLASHROM_READ */ - /* TODO */ - cpu->cd.sh.r[0] = (uint32_t) -1; - break; - default:fatal("[ FLASHROM: Unimplemented r7=%i ]\n", r7); - goto bad; - } - break; - - case 0x8c0000bc: - switch ((int32_t)r6) { - case 0: /* GD-ROM emulation */ - switch (r7) { - case 0: /* GDROM_SEND_COMMAND */ - /* TODO */ - cpu->cd.sh.r[0] = (uint32_t) -1; - break; - case 1: /* GDROM_CHECK_COMMAND */ - /* TODO */ - cpu->cd.sh.r[0] = 0; - break; - case 2: /* GDROM_MAINLOOP */ - /* TODO */ - break; - case 3: /* GDROM_INIT */ - /* TODO: Do something here? */ - break; - case 4: /* GDROM_CHECK_DRIVE */ - /* TODO: Return status words */ - break; - default:fatal("[ GDROM: Unimplemented r7=%i ]\n", r7); - goto bad; - } - break; - default:fatal("[ 0xbc: Unimplemented r6=0x%x ]\n", r6); - goto bad; - } - break; - - case 0x8c0000e0: - /* - * This seems to have two uses: - * - * 1. KallistiOS calls this from arch_menu(), i.e. to return - * from a running program. - * 2. The "licence code" in the IP.BIN code when booting from - * a bootable CD image calls this once the license screen - * has been displayed, and it wants the ROM to jump to - * 0x8c00b800 ("Bootstrap 1"). - * - * The easiest way to support both is probably to keep track - * of whether the IP.BIN code was started by the (software) - * ROM emulation code, or not. - */ - if (booting_from_cdrom) { - debug("[ dreamcast: Switching to bootstrap 1 ]\n"); - - booting_from_cdrom = 0; - - // Jump to bootstrap 1 - cpu->pc = 0x8c00b800; - return; - } else { - fatal("[ dreamcast: Returning to main menu. ]\n"); - cpu->running = 0; - } - break; - - case 0x8c0000f0: - /* - * GXemul hack: - * - * The vector (word) at 0x8c0000f0 contains the value 0x8c000140. - * - * By jumping to this address (0x8c000140), a "boot from - * CDROM" is simulated. Control is transfered to the license - * code in the loaded IP.BIN file. - */ - debug("[ dreamcast boot from CDROM ]\n"); - booting_from_cdrom = 1; - cpu->pc = 0x8c008300; - return; - - default:goto bad; - } - - /* Return from subroutine: */ - cpu->pc = cpu->cd.sh.pr; - - return; - -bad: - cpu_register_dump(cpu->machine, cpu, 1, 0); - printf("\n"); - fatal("[ dreamcast_emul(): unimplemented dreamcast PROM call, " - "pc=0x%08" PRIx32" (vectorAddr=0x%08" PRIx32") ]\n", (uint32_t)cpu->pc, vectorAddr); - cpu->running = 0; - return; -} - diff -Nru gxemul-0.6.2/src/promemul/dreamcast_scramble.c gxemul-0.7.0+dfsg/src/promemul/dreamcast_scramble.c --- gxemul-0.6.2/src/promemul/dreamcast_scramble.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/dreamcast_scramble.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,278 @@ +/* + * COMMENT: Dreamcast emulation (helper module) + * + * This is from Marcus Comstedt's Dreamcast development files + * (http://mc.pp.se/dc/files/scramble.c). Public Domain, according to + * Marcus software page. + * + * The only modification done to make it fit into the emulator is that + * it is executed internally from src/file.c. + */ + +/* #define STAND_ALONE */ + +#include +#include +#include + +#define MAXCHUNK (2048*1024) + +static unsigned int seed; + +void my_srand(unsigned int n) +{ + seed = n & 0xffff; +} + +unsigned int my_rand(void) +{ + seed = (seed * 2109 + 9273) & 0x7fff; + return (seed + 0xc000) & 0xffff; +} + +void load(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + if(fread(ptr, 1, sz, fh) != sz) + { + fprintf(stderr, "Read error!\n"); + exit(1); + } +} + +void load_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + static int idx[MAXCHUNK/32]; + int i; + + /* Convert chunk size to number of slices */ + sz /= 32; + + /* Initialize index table with unity, + so that each slice gets loaded exactly once */ + for(i = 0; i < (int)sz; i++) + idx[i] = i; + + for(i = sz-1; i >= 0; --i) + { + /* Select a replacement index */ + int x = (my_rand() * i) >> 16; + + /* Swap */ + int tmp = idx[i]; + idx[i] = idx[x]; + idx[x] = tmp; + + /* Load resulting slice */ + load(fh, ptr+32*idx[i], 32); + } +} + +void load_file(FILE *fh, unsigned char *ptr, unsigned long filesz) +{ + unsigned long chunksz; + + my_srand(filesz); + + /* Descramble 2 meg blocks for as long as possible, then + gradually reduce the window down to 32 bytes (1 slice) */ + for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) + while(filesz >= chunksz) + { + load_chunk(fh, ptr, chunksz); + filesz -= chunksz; + ptr += chunksz; + } + + /* Load final incomplete slice */ + if(filesz) + load(fh, ptr, filesz); +} + +void read_file(char *filename, unsigned char **ptr, unsigned long *sz) +{ + FILE *fh = fopen(filename, "rb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", filename); + exit(1); + } + if(fseek(fh, 0, SEEK_END)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + *sz = ftell(fh); + *ptr = (unsigned char *) malloc(*sz); + if( *ptr == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + if(fseek(fh, 0, SEEK_SET)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + load_file(fh, *ptr, *sz); + fclose(fh); +} + +void save(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + if(fwrite(ptr, 1, sz, fh) != sz) + { + fprintf(stderr, "Write error!\n"); + exit(1); + } +} + +void save_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) +{ + static int idx[MAXCHUNK/32]; + int i; + + /* Convert chunk size to number of slices */ + sz /= 32; + + /* Initialize index table with unity, + so that each slice gets saved exactly once */ + for(i = 0; i < (int)sz; i++) + idx[i] = i; + + for(i = sz-1; i >= 0; --i) + { + /* Select a replacement index */ + int x = (my_rand() * i) >> 16; + + /* Swap */ + int tmp = idx[i]; + idx[i] = idx[x]; + idx[x] = tmp; + + /* Save resulting slice */ + save(fh, ptr+32*idx[i], 32); + } +} + +void save_file(FILE *fh, unsigned char *ptr, unsigned long filesz) +{ + unsigned long chunksz; + + my_srand(filesz); + + /* Descramble 2 meg blocks for as long as possible, then + gradually reduce the window down to 32 bytes (1 slice) */ + for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) + while(filesz >= chunksz) + { + save_chunk(fh, ptr, chunksz); + filesz -= chunksz; + ptr += chunksz; + } + + /* Save final incomplete slice */ + if(filesz) + save(fh, ptr, filesz); +} + +void write_file(char *filename, unsigned char *ptr, unsigned long sz) +{ + FILE *fh = fopen(filename, "wb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", filename); + exit(1); + } + save_file(fh, ptr, sz); + fclose(fh); +} + +void dreamcast_descramble(char *src, char *dst) +{ + unsigned char *ptr = NULL; + unsigned long sz = 0; + FILE *fh; + + read_file(src, &ptr, &sz); + + fh = fopen(dst, "wb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", dst); + exit(1); + } + if( fwrite(ptr, 1, sz, fh) != sz ) + { + fprintf(stderr, "Write error.\n"); + exit(1); + } + fclose(fh); + free(ptr); +} + +void scramble(char *src, char *dst) +{ + unsigned char *ptr = NULL; + unsigned long sz = 0; + FILE *fh; + + fh = fopen(src, "rb"); + if(fh == NULL) + { + fprintf(stderr, "Can't open \"%s\".\n", src); + exit(1); + } + if(fseek(fh, 0, SEEK_END)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + sz = ftell(fh); + ptr = (unsigned char *) malloc(sz); + if( ptr == NULL ) + { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + if(fseek(fh, 0, SEEK_SET)<0) + { + fprintf(stderr, "Seek error.\n"); + exit(1); + } + if( fread(ptr, 1, sz, fh) != sz ) + { + fprintf(stderr, "Read error.\n"); + exit(1); + } + fclose(fh); + + write_file(dst, ptr, sz); + + free(ptr); +} + + +#ifdef STAND_ALONE + +int main(int argc, char *argv[]) +{ + int opt = 0; + + if(argc > 1 && !strcmp(argv[1], "-d")) + opt ++; + + if(argc != 3+opt) + { + fprintf(stderr, "Usage: %s [-d] from to\n", argv[0]); + exit(1); + } + + if(opt) + dreamcast_descramble(argv[2], argv[3]); + else + scramble(argv[1], argv[2]); + + return 0; +} + +#endif diff -Nru gxemul-0.6.2/src/promemul/dreamcast_scramble.cc gxemul-0.7.0+dfsg/src/promemul/dreamcast_scramble.cc --- gxemul-0.6.2/src/promemul/dreamcast_scramble.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/dreamcast_scramble.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,278 +0,0 @@ -/* - * COMMENT: Dreamcast emulation (helper module) - * - * This is from Marcus Comstedt's Dreamcast development files - * (http://mc.pp.se/dc/files/scramble.c). Public Domain, according to - * Marcus software page. - * - * The only modification done to make it fit into the emulator is that - * it is executed internally from src/file.c. - */ - -/* #define STAND_ALONE */ - -#include -#include -#include - -#define MAXCHUNK (2048*1024) - -static unsigned int seed; - -void my_srand(unsigned int n) -{ - seed = n & 0xffff; -} - -unsigned int my_rand(void) -{ - seed = (seed * 2109 + 9273) & 0x7fff; - return (seed + 0xc000) & 0xffff; -} - -void load(FILE *fh, unsigned char *ptr, unsigned long sz) -{ - if(fread(ptr, 1, sz, fh) != sz) - { - fprintf(stderr, "Read error!\n"); - exit(1); - } -} - -void load_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) -{ - static int idx[MAXCHUNK/32]; - int i; - - /* Convert chunk size to number of slices */ - sz /= 32; - - /* Initialize index table with unity, - so that each slice gets loaded exactly once */ - for(i = 0; i < (int)sz; i++) - idx[i] = i; - - for(i = sz-1; i >= 0; --i) - { - /* Select a replacement index */ - int x = (my_rand() * i) >> 16; - - /* Swap */ - int tmp = idx[i]; - idx[i] = idx[x]; - idx[x] = tmp; - - /* Load resulting slice */ - load(fh, ptr+32*idx[i], 32); - } -} - -void load_file(FILE *fh, unsigned char *ptr, unsigned long filesz) -{ - unsigned long chunksz; - - my_srand(filesz); - - /* Descramble 2 meg blocks for as long as possible, then - gradually reduce the window down to 32 bytes (1 slice) */ - for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) - while(filesz >= chunksz) - { - load_chunk(fh, ptr, chunksz); - filesz -= chunksz; - ptr += chunksz; - } - - /* Load final incomplete slice */ - if(filesz) - load(fh, ptr, filesz); -} - -void read_file(char *filename, unsigned char **ptr, unsigned long *sz) -{ - FILE *fh = fopen(filename, "rb"); - if(fh == NULL) - { - fprintf(stderr, "Can't open \"%s\".\n", filename); - exit(1); - } - if(fseek(fh, 0, SEEK_END)<0) - { - fprintf(stderr, "Seek error.\n"); - exit(1); - } - *sz = ftell(fh); - *ptr = (unsigned char *) malloc(*sz); - if( *ptr == NULL ) - { - fprintf(stderr, "Out of memory.\n"); - exit(1); - } - if(fseek(fh, 0, SEEK_SET)<0) - { - fprintf(stderr, "Seek error.\n"); - exit(1); - } - load_file(fh, *ptr, *sz); - fclose(fh); -} - -void save(FILE *fh, unsigned char *ptr, unsigned long sz) -{ - if(fwrite(ptr, 1, sz, fh) != sz) - { - fprintf(stderr, "Write error!\n"); - exit(1); - } -} - -void save_chunk(FILE *fh, unsigned char *ptr, unsigned long sz) -{ - static int idx[MAXCHUNK/32]; - int i; - - /* Convert chunk size to number of slices */ - sz /= 32; - - /* Initialize index table with unity, - so that each slice gets saved exactly once */ - for(i = 0; i < (int)sz; i++) - idx[i] = i; - - for(i = sz-1; i >= 0; --i) - { - /* Select a replacement index */ - int x = (my_rand() * i) >> 16; - - /* Swap */ - int tmp = idx[i]; - idx[i] = idx[x]; - idx[x] = tmp; - - /* Save resulting slice */ - save(fh, ptr+32*idx[i], 32); - } -} - -void save_file(FILE *fh, unsigned char *ptr, unsigned long filesz) -{ - unsigned long chunksz; - - my_srand(filesz); - - /* Descramble 2 meg blocks for as long as possible, then - gradually reduce the window down to 32 bytes (1 slice) */ - for(chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) - while(filesz >= chunksz) - { - save_chunk(fh, ptr, chunksz); - filesz -= chunksz; - ptr += chunksz; - } - - /* Save final incomplete slice */ - if(filesz) - save(fh, ptr, filesz); -} - -void write_file(char *filename, unsigned char *ptr, unsigned long sz) -{ - FILE *fh = fopen(filename, "wb"); - if(fh == NULL) - { - fprintf(stderr, "Can't open \"%s\".\n", filename); - exit(1); - } - save_file(fh, ptr, sz); - fclose(fh); -} - -void dreamcast_descramble(char *src, char *dst) -{ - unsigned char *ptr = NULL; - unsigned long sz = 0; - FILE *fh; - - read_file(src, &ptr, &sz); - - fh = fopen(dst, "wb"); - if(fh == NULL) - { - fprintf(stderr, "Can't open \"%s\".\n", dst); - exit(1); - } - if( fwrite(ptr, 1, sz, fh) != sz ) - { - fprintf(stderr, "Write error.\n"); - exit(1); - } - fclose(fh); - free(ptr); -} - -void scramble(char *src, char *dst) -{ - unsigned char *ptr = NULL; - unsigned long sz = 0; - FILE *fh; - - fh = fopen(src, "rb"); - if(fh == NULL) - { - fprintf(stderr, "Can't open \"%s\".\n", src); - exit(1); - } - if(fseek(fh, 0, SEEK_END)<0) - { - fprintf(stderr, "Seek error.\n"); - exit(1); - } - sz = ftell(fh); - ptr = (unsigned char *) malloc(sz); - if( ptr == NULL ) - { - fprintf(stderr, "Out of memory.\n"); - exit(1); - } - if(fseek(fh, 0, SEEK_SET)<0) - { - fprintf(stderr, "Seek error.\n"); - exit(1); - } - if( fread(ptr, 1, sz, fh) != sz ) - { - fprintf(stderr, "Read error.\n"); - exit(1); - } - fclose(fh); - - write_file(dst, ptr, sz); - - free(ptr); -} - - -#ifdef STAND_ALONE - -int main(int argc, char *argv[]) -{ - int opt = 0; - - if(argc > 1 && !strcmp(argv[1], "-d")) - opt ++; - - if(argc != 3+opt) - { - fprintf(stderr, "Usage: %s [-d] from to\n", argv[0]); - exit(1); - } - - if(opt) - dreamcast_descramble(argv[2], argv[3]); - else - scramble(argv[1], argv[2]); - - return 0; -} - -#endif diff -Nru gxemul-0.6.2/src/promemul/.index gxemul-0.7.0+dfsg/src/promemul/.index --- gxemul-0.6.2/src/promemul/.index 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/.index 2021-11-27 09:42:23.000000000 +0000 @@ -1,10 +1,10 @@ -arcbios.cc ARCBIOS and ARCS emulation -dec_prom.cc DECstation PROM emulation -dreamcast.cc Dreamcast PROM emulation -dreamcast_scramble.cc Dreamcast emulation (helper module) -luna88kprom.cc LUNA 88K PROM emulation -mvmeprom.cc MVME PROM emulation -of.cc OpenFirmware emulation -ps2_bios.cc Playstation 2 SIFBIOS emulation -sh_ipl_g.cc SH-IPL+G emulation -yamon.cc YAMON emulation +arcbios.c ARCBIOS and ARCS emulation +dec_prom.c DECstation PROM emulation +dreamcast.c Dreamcast PROM emulation +dreamcast_scramble.c Dreamcast emulation (helper module) +luna88kprom.c LUNA 88K PROM emulation +mvmeprom.c MVME PROM emulation +of.c OpenFirmware emulation +ps2_bios.c Playstation 2 SIFBIOS emulation +sh_ipl_g.c SH-IPL+G emulation +yamon.c YAMON emulation diff -Nru gxemul-0.6.2/src/promemul/luna88kprom.c gxemul-0.7.0+dfsg/src/promemul/luna88kprom.c --- gxemul-0.6.2/src/promemul/luna88kprom.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/luna88kprom.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018-2021 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: LUNA 88K PROM emulation + * + * For LUNA 88K emulation. + */ + +#include +#include +#include +#include + +#include "console.h" +#include "cpu.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + +#include "thirdparty/luna88k_board.h" + + +/* + * luna88kprom_init(): + */ +void luna88kprom_init(struct machine *machine) +{ + struct cpu *cpu = machine->cpus[0]; + + /* + * Memory layout according to OpenBSD's locore0.S: + * + * 0x00000 - 0x00fff = trap vectors + * 0x01000 - 0x1ffff = ROM monitor work area + * 0x20000 - ... = Boot loader jumps here + * + * The boot loader stage before loading OpenBSD's kernel seems + * to be loaded at 0x00700000. + */ + + /* 0x00001100: ROM function table. See OpenBSD's machdep.c */ + store_32bit_word(cpu, 0x1100 + sizeof(uint32_t) * 3, 0x2030); /* ROM console getch */ + store_32bit_word(cpu, 0x1100 + sizeof(uint32_t) * 4, 0x2040); /* ROM console putch */ + + store_32bit_word(cpu, 0x2030, M88K_PROM_INSTR); + store_32bit_word(cpu, 0x2034, 0xf400c001); /* jmp (r1) */ + + store_32bit_word(cpu, 0x2040, M88K_PROM_INSTR); + store_32bit_word(cpu, 0x2044, 0xf400c001); /* jmp (r1) */ + + /* 0x00001114: Framebuffer depth */ + store_32bit_word(cpu, 0x1114, machine->x11_md.in_use ? 1 : 0); +} + + +/* + * luna88kprom_emul(): + * + * Input: + * pc is used to figure out function number + * r2 = first argument (for functions that take arguments) + * + * Output: + * r2 = result + */ +int luna88kprom_emul(struct cpu *cpu) +{ + int func = (cpu->pc & 0xf0) >> 4; + + switch (func) { + + case 4: + debugmsg(SUBSYS_PROMEMUL, "luna88k", VERBOSITY_DEBUG, "putchar 0x%02x", cpu->cd.m88k.r[2]); + console_putchar(cpu->machine->main_console_handle, cpu->cd.m88k.r[2]); + break; + + default: + cpu_register_dump(cpu->machine, cpu, 1, 0); + cpu_register_dump(cpu->machine, cpu, 0, 1); + debugmsg(SUBSYS_PROMEMUL, "luna88k", VERBOSITY_ERROR, "unimplemented function 0x%" PRIx32, func); + cpu->running = 0; + return 0; + } + + return 1; +} + diff -Nru gxemul-0.6.2/src/promemul/luna88kprom.cc gxemul-0.7.0+dfsg/src/promemul/luna88kprom.cc --- gxemul-0.6.2/src/promemul/luna88kprom.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/luna88kprom.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2018 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: LUNA 88K PROM emulation - * - * For LUNA 88K emulation. - */ - -#include -#include -#include -#include - -#include "console.h" -#include "cpu.h" -#include "machine.h" -#include "memory.h" -#include "misc.h" - -#include "thirdparty/luna88k_board.h" - - -/* - * luna88kprom_init(): - */ -void luna88kprom_init(struct machine *machine) -{ - struct cpu *cpu = machine->cpus[0]; - - /* - * Memory layout according to OpenBSD's locore0.S: - * - * 0x00000 - 0x00fff = trap vectors - * 0x01000 - 0x1ffff = ROM monitor work area - * 0x20000 - ... = Boot loader jumps here - * - * The boot loader stage before loading OpenBSD's kernel seems - * to be loaded at 0x00700000. - */ - - /* 0x00001100: ROM function table. See OpenBSD's machdep.c */ - store_32bit_word(cpu, 0x1100 + sizeof(uint32_t) * 3, 0x2030); /* ROM console getch */ - store_32bit_word(cpu, 0x1100 + sizeof(uint32_t) * 4, 0x2040); /* ROM console putch */ - - store_32bit_word(cpu, 0x2030, M88K_PROM_INSTR); - store_32bit_word(cpu, 0x2034, 0xf400c001); /* jmp (r1) */ - - store_32bit_word(cpu, 0x2040, M88K_PROM_INSTR); - store_32bit_word(cpu, 0x2044, 0xf400c001); /* jmp (r1) */ - - /* 0x00001114: Framebuffer depth */ - store_32bit_word(cpu, 0x1114, machine->x11_md.in_use ? 8 : 0); -} - - -/* - * luna88kprom_emul(): - * - * Input: - * pc is used to figure out function number - * r2 = first argument (for functions that take arguments) - * - * Output: - * r2 = result - */ -int luna88kprom_emul(struct cpu *cpu) -{ - int func = (cpu->pc & 0xf0) >> 4; - - switch (func) { - - case 4: - console_putchar(cpu->machine->main_console_handle, cpu->cd.m88k.r[2]); - break; - - default: - cpu_register_dump(cpu->machine, cpu, 1, 0); - cpu_register_dump(cpu->machine, cpu, 0, 1); - fatal("[ LUNA88K PROM emulation: unimplemented function 0x%" PRIx32" ]\n", func); - cpu->running = 0; - return 0; - } - - return 1; -} - diff -Nru gxemul-0.6.2/src/promemul/Makefile.skel gxemul-0.7.0+dfsg/src/promemul/Makefile.skel --- gxemul-0.6.2/src/promemul/Makefile.skel 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/Makefile.skel 2021-11-27 09:42:23.000000000 +0000 @@ -2,7 +2,7 @@ # Makefile for GXemul src/promemul # -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) +CFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) OBJS=arcbios.o dec_prom.o dreamcast.o dreamcast_scramble.o \ luna88kprom.o mvmeprom.o of.o ps2_bios.o sh_ipl_g.o yamon.o diff -Nru gxemul-0.6.2/src/promemul/mvmeprom.c gxemul-0.7.0+dfsg/src/promemul/mvmeprom.c --- gxemul-0.6.2/src/promemul/mvmeprom.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/mvmeprom.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007-2009 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: MVME PROM emulation + * + * For mvme88k emulation. + * + * TODO: Perhaps this could be reused for mvme68k emulation too? + */ + +#include +#include +#include +#include + +#include "console.h" +#include "cpu.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + +#include "thirdparty/mvmeprom.h" + + +#define MVMEPROM_BRDID_ADDR 0x1100 + + +/* + * mvmeprom_init(): + */ +void mvmeprom_init(struct machine *machine) +{ + struct cpu *cpu = machine->cpus[0]; + struct mvmeprom_brdid mvmeprom_brdid; + uint32_t vbr = 0x00000000; + int model = 0x187; + + switch (machine->machine_subtype) { + case MACHINE_MVME88K_187: model = 0x187; break; + case MACHINE_MVME88K_188: model = 0x188; break; + case MACHINE_MVME88K_197: model = 0x197; break; + } + + cpu->cd.m88k.cr[M88K_CR_VBR] = vbr; + + /* A magic prom call instruction, followed by an 'rte': */ + store_32bit_word(cpu, vbr + 8 * MVMEPROM_VECTOR, M88K_PROM_INSTR); + store_32bit_word(cpu, vbr + 8 * MVMEPROM_VECTOR + 4, 0xf400fc00); + + /* brdid struct: */ + memset(&mvmeprom_brdid, 0, sizeof(mvmeprom_brdid)); + store_16bit_word_in_host(cpu, (unsigned char *) + &(mvmeprom_brdid.model), model); + mvmeprom_brdid.speed[0] = '3'; /* 33 MHz, for now */ + mvmeprom_brdid.speed[1] = '3'; + mvmeprom_brdid.speed[2] = '0'; + mvmeprom_brdid.speed[3] = '0'; + store_buf(cpu, MVMEPROM_BRDID_ADDR, + (char *)&mvmeprom_brdid, sizeof(struct mvmeprom_brdid)); +} + + +/* + * mvmeprom_emul(): + * + * For MVME88K: + * + * Input: + * r9 = requested function number + * r2 = first argument (for functions that take arguments) + * + * Output: + * r2 = result + */ +int mvmeprom_emul(struct cpu *cpu) +{ + int func = cpu->cd.m88k.r[9]; + + switch (func) { + + case MVMEPROM_OUTCHR: + console_putchar(cpu->machine->main_console_handle, + cpu->cd.m88k.r[2]); + break; + + case MVMEPROM_OUTCRLF: + console_putchar(cpu->machine->main_console_handle, '\n'); + break; + + case MVMEPROM_EXIT: + fatal("[ MVME PROM: exit ]\n"); + cpu->running = 0; + break; + + case MVMEPROM_GETBRDID: + /* Return a pointer in r2 to a mvmeprom_brdid struct. */ + cpu->cd.m88k.r[2] = MVMEPROM_BRDID_ADDR; + break; + + default: + cpu_register_dump(cpu->machine, cpu, 1, 0); + cpu_register_dump(cpu->machine, cpu, 0, 1); + fatal("[ MVME PROM emulation: unimplemented function 0x%" + PRIx32" ]\n", func); + cpu->running = 0; + return 0; + } + + return 1; +} + diff -Nru gxemul-0.6.2/src/promemul/mvmeprom.cc gxemul-0.7.0+dfsg/src/promemul/mvmeprom.cc --- gxemul-0.6.2/src/promemul/mvmeprom.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/mvmeprom.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2007-2009 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: MVME PROM emulation - * - * For mvme88k emulation. - * - * TODO: Perhaps this could be reused for mvme68k emulation too? - */ - -#include -#include -#include -#include - -#include "console.h" -#include "cpu.h" -#include "machine.h" -#include "memory.h" -#include "misc.h" - -#include "thirdparty/mvmeprom.h" - - -#define MVMEPROM_BRDID_ADDR 0x1100 - - -/* - * mvmeprom_init(): - */ -void mvmeprom_init(struct machine *machine) -{ - struct cpu *cpu = machine->cpus[0]; - struct mvmeprom_brdid mvmeprom_brdid; - uint32_t vbr = 0x00000000; - int model = 0x187; - - switch (machine->machine_subtype) { - case MACHINE_MVME88K_187: model = 0x187; break; - case MACHINE_MVME88K_188: model = 0x188; break; - case MACHINE_MVME88K_197: model = 0x197; break; - } - - cpu->cd.m88k.cr[M88K_CR_VBR] = vbr; - - /* A magic prom call instruction, followed by an 'rte': */ - store_32bit_word(cpu, vbr + 8 * MVMEPROM_VECTOR, M88K_PROM_INSTR); - store_32bit_word(cpu, vbr + 8 * MVMEPROM_VECTOR + 4, 0xf400fc00); - - /* brdid struct: */ - memset(&mvmeprom_brdid, 0, sizeof(mvmeprom_brdid)); - store_16bit_word_in_host(cpu, (unsigned char *) - &(mvmeprom_brdid.model), model); - mvmeprom_brdid.speed[0] = '3'; /* 33 MHz, for now */ - mvmeprom_brdid.speed[1] = '3'; - mvmeprom_brdid.speed[2] = '0'; - mvmeprom_brdid.speed[3] = '0'; - store_buf(cpu, MVMEPROM_BRDID_ADDR, - (char *)&mvmeprom_brdid, sizeof(struct mvmeprom_brdid)); -} - - -/* - * mvmeprom_emul(): - * - * For MVME88K: - * - * Input: - * r9 = requested function number - * r2 = first argument (for functions that take arguments) - * - * Output: - * r2 = result - */ -int mvmeprom_emul(struct cpu *cpu) -{ - int func = cpu->cd.m88k.r[9]; - - switch (func) { - - case MVMEPROM_OUTCHR: - console_putchar(cpu->machine->main_console_handle, - cpu->cd.m88k.r[2]); - break; - - case MVMEPROM_OUTCRLF: - console_putchar(cpu->machine->main_console_handle, '\n'); - break; - - case MVMEPROM_EXIT: - fatal("[ MVME PROM: exit ]\n"); - cpu->running = 0; - break; - - case MVMEPROM_GETBRDID: - /* Return a pointer in r2 to a mvmeprom_brdid struct. */ - cpu->cd.m88k.r[2] = MVMEPROM_BRDID_ADDR; - break; - - default: - cpu_register_dump(cpu->machine, cpu, 1, 0); - cpu_register_dump(cpu->machine, cpu, 0, 1); - fatal("[ MVME PROM emulation: unimplemented function 0x%" - PRIx32" ]\n", func); - cpu->running = 0; - return 0; - } - - return 1; -} - diff -Nru gxemul-0.6.2/src/promemul/of.c gxemul-0.7.0+dfsg/src/promemul/of.c --- gxemul-0.6.2/src/promemul/of.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/of.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,1191 @@ +/* + * Copyright (C) 2005-2021 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: OpenFirmware emulation + * + * NOTE: This module is/was a quick hack, with the purpose of getting + * NetBSD/macppc to boot. If anything else boots using this hackish + * implementation of OpenFirmware, then that is a bonus. + * + ****************************************************************************** + * + * NOTE: OpenFirmware is used on quite a variety of different hardware archs, + * at least POWER/PowerPC, ARM, and SPARC, so the code in this module + * must always remain architecture agnostic. + * + * NOTE: Some things, e.g. 32-bit integers as returned by the "getprop" + * service, are always fixed to big-endian. (According to the standard.) + * + * TODO: o) 64-bit OpenFirmware? + * o) More devices... + */ + +#include +#include +#include +#include + +#define OF_C + +#include "console.h" +#include "cpu.h" +#include "device.h" +#include "devices.h" +#include "diskimage.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" +#include "of.h" + + +/* #define debug fatal */ + +extern int quiet_mode; +extern int verbose; + + +/* + * readstr(): + * + * Helper function to read a string from emulated memory. + */ +static void readstr(struct cpu *cpu, uint64_t addr, char *strbuf, + int bufsize) +{ + int i; + for (i=0; imemory_rw(cpu, cpu->mem, addr + i, + &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); + strbuf[i] = '\0'; + if (ch >= 1 && ch < 32) + ch = 0; + strbuf[i] = ch; + if (strbuf[i] == '\0') + break; + } + + strbuf[bufsize - 1] = '\0'; +} + + +/* + * of_store_32bit_in_host(): + * + * Store big-endian. OpenFirmware properties returned by getprop etc are + * always big-endian, even on little-endian machines. + */ +static void of_store_32bit_in_host(unsigned char *d, uint32_t x) +{ + d[0] = x >> 24; d[1] = x >> 16; + d[2] = x >> 8; d[3] = x; +} + + +/* + * find_device_handle(): + * + * name may consist of multiple names, separated with slashes. + */ +static int find_device_handle(struct of_data *ofd, const char *name) +{ + int handle = 1, cur_parent = 1; + + if (name[0] == 0) + return 0; + + for (;;) { + struct of_device *od = ofd->of_devices; + char tmp[200]; + int i; + + while (name[0] == '/') + name++; + if (name[0] == '\0') + break; + snprintf(tmp, sizeof(tmp), "%s", name); + i = 0; + while (tmp[i] != '\0' && tmp[i] != '/') + i++; + tmp[i] = '\0'; + + OF_FIND(od, strcmp(od->name, tmp) == 0 && + od->parent == cur_parent); + if (od == NULL) + return -1; + + handle = cur_parent = od->handle; + name += strlen(tmp); + } + + return handle; +} + + +/*****************************************************************************/ + + +OF_SERVICE(call_method_2_2) +{ + fatal("[ of: call_method_2_2('%s'): TODO ]\n", arg[0]); + return -1; +} + + +OF_SERVICE(call_method_3_4) +{ + fatal("[ of: call_method_3_4('%s'): TODO ]\n", arg[0]); + return -1; +} + + +OF_SERVICE(call_method_5_2) +{ + if (strcmp(arg[0], "set-colors") == 0) { + /* Used by OpenBSD/macppc: */ + struct vfb_data *v = cpu->machine->md.of_data->vfb_data; + int color = OF_GET_ARG(3); + uint64_t ptr = OF_GET_ARG(4); + unsigned char rgb[3]; + cpu->memory_rw(cpu, cpu->mem, ptr, rgb, 3, MEM_READ, + CACHE_DATA | NO_EXCEPTIONS); + if (v != NULL) { + memcpy(v->rgb_palette + 3 * color, rgb, 3); + v->update_x1 = v->update_y1 = 0; + v->update_x2 = v->xsize - 1; + v->update_y2 = v->ysize - 1; + } + } else { + fatal("[ of: call_method_5_2('%s'): TODO ]\n", arg[0]); + return -1; + } + return 0; +} + + +OF_SERVICE(call_method_6_1) +{ + fatal("[ of: call_method_6_1('%s'): TODO ]\n", arg[0]); + return -1; +} + + +OF_SERVICE(call_method_6_2) +{ + fatal("[ of: call_method_6_2('%s'): TODO ]\n", arg[0]); + return -1; +} + + +OF_SERVICE(child) +{ + struct of_device *od = cpu->machine->md.of_data->of_devices; + int handle = OF_GET_ARG(0); + OF_FIND(od, od->parent == handle); + store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->handle); + return 0; +} + + +OF_SERVICE(claim) +{ + // Arguments: virtualaddr, size, alignment + // Returns: pointer to claimed memory + + // TODO: This is just a dummy. + fatal("[ of: claim(0x%x,0x%x,0x%x): TODO ]\n", + OF_GET_ARG(0), OF_GET_ARG(1), OF_GET_ARG(2)); + + store_32bit_word(cpu, base + retofs, OF_GET_ARG(0)); + return 0; +} + + +OF_SERVICE(exit) +{ + cpu->running = 0; + return 0; +} + + +OF_SERVICE(finddevice) +{ + int h = find_device_handle(cpu->machine->md.of_data, arg[0]); + store_32bit_word(cpu, base + retofs, h); + return h>0? 0 : -1; +} + + +OF_SERVICE(getprop) +{ + struct of_device *od = cpu->machine->md.of_data->of_devices; + struct of_device_property *pr; + int handle = OF_GET_ARG(0), i, len_returned = 0; + uint64_t buf = OF_GET_ARG(2); + uint64_t max = OF_GET_ARG(3); + + OF_FIND(od, od->handle == handle); + if (od == NULL) { + fatal("[ of: WARNING: getprop handle=%i; no such handle ]\n", + handle); + return -1; + } + + pr = od->properties; + OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); + if (pr == NULL) { + fatal("[ of: WARNING: getprop: no property '%s' at handle" + " %i (device '%s') ]\n", arg[1], handle, od->name); + return -1; + } + + if (pr->data == NULL) { + fatal("[ of: WARNING: property '%s' of '%s' has no data! ]\n", + arg[1], od->name); + goto ret; + } + + /* Return the property into emulated RAM: */ + len_returned = pr->len <= max? pr->len : max; + + for (i=0; imemory_rw(cpu, cpu->mem, buf + i, pr->data + i, + 1, MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS)) { + fatal("[ of: getprop memory_rw() error ]\n"); + exit(1); + } + } + +ret: + store_32bit_word(cpu, base + retofs, len_returned); + return 0; +} + + +OF_SERVICE(getproplen) +{ + struct of_device *od = cpu->machine->md.of_data->of_devices; + struct of_device_property *pr; + int handle = OF_GET_ARG(0); + + OF_FIND(od, od->handle == handle); + if (od == NULL) { + fatal("[ of: TODO: getproplen handle=%i; no such handle ]\n", + handle); + return -1; + } + + pr = od->properties; + OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); + if (pr == NULL) { + fatal("[ of: TODO: getproplen: no property '%s' at handle" + " %i (device '%s') ]\n", arg[1], handle, od->name); + return -1; + } + + store_32bit_word(cpu, base + retofs, pr->len); + return 0; +} + + +OF_SERVICE(instance_to_package) +{ + int handle = OF_GET_ARG(0); + /* TODO: actually do something here? :-) */ + store_32bit_word(cpu, base + retofs, handle); + return 0; +} + + +OF_SERVICE(interpret_1) +{ + if (strcmp(arg[0], "#lines 2 - to line#") == 0) { + } else { + fatal("[ of: interpret_1('%s'): TODO ]\n", arg[0]); + return -1; + } + return 0; +} + + +OF_SERVICE(interpret_2) +{ + store_32bit_word(cpu, base + retofs, 0); /* ? TODO */ + if (strcmp(arg[0], "#columns") == 0) { + store_32bit_word(cpu, base + retofs + 4, 80); + } else if (strcmp(arg[0], "#lines") == 0) { + store_32bit_word(cpu, base + retofs + 4, 40); + } else if (strcmp(arg[0], "char-height") == 0) { + store_32bit_word(cpu, base + retofs + 4, 15); + } else if (strcmp(arg[0], "char-width") == 0) { + store_32bit_word(cpu, base + retofs + 4, 10); + } else if (strcmp(arg[0], "line#") == 0) { + store_32bit_word(cpu, base + retofs + 4, 0); + } else if (strcmp(arg[0], "font-adr") == 0) { + store_32bit_word(cpu, base + retofs + 4, 0); + } else { + fatal("[ of: interpret_2('%s'): TODO ]\n", arg[0]); + return -1; + } + return 0; +} + + +OF_SERVICE(package_to_path) +{ + fatal("[ of: package-to-path: TODO ]\n"); + return -1; +} + + +OF_SERVICE(parent) +{ + struct of_device *od = cpu->machine->md.of_data->of_devices; + int handle = OF_GET_ARG(0); + OF_FIND(od, od->handle == handle); + store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->parent); + return 0; +} + + +OF_SERVICE(peer) +{ + struct of_device *od = cpu->machine->md.of_data->of_devices; + int handle = OF_GET_ARG(0), parent = 0, peer = 0, seen_self = 1; + + if (handle == 0) { + /* Return the handle of the root node (1): */ + store_32bit_word(cpu, base + retofs, 1); + return 0; + } + + OF_FIND(od, od->handle == handle); + if (od == NULL) { + fatal("[ of: TODO: peer(): can't find handle %i ]\n", handle); + exit(1); + } + parent = od->parent; + seen_self = 0; + + od = cpu->machine->md.of_data->of_devices; + + while (od != NULL) { + if (od->parent == parent) { + if (seen_self) { + peer = od->handle; + break; + } + if (od->handle == handle) + seen_self = 1; + } + od = od->next; + } + store_32bit_word(cpu, base + retofs, peer); + return 0; +} + + +OF_SERVICE(open) +{ + // TODO. + uint64_t ptr = OF_GET_ARG(0); + + unsigned char s[2000]; + int s_len = 0; + + int i = 0; + for (;;) { + unsigned char ch; + if (!cpu->memory_rw(cpu, cpu->mem, ptr + i, &ch, + 1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) { + fatal("[ of: TODO: write: memory_rw() error ]\n"); + exit(1); + } + + if (ch == 0) + break; + + s[s_len++] = ch; + if (s_len == sizeof(s) - 1) + break; + ++ i; + } + + s[s_len] = 0; + + if (s[0]) { + printf("Unimplemented OF_SERVICE(open) with name: '%s'\n", s); + exit(1); + } + + return 0; +} + + +OF_SERVICE(read) +{ + /* int handle = OF_GET_ARG(0); */ + uint64_t ptr = OF_GET_ARG(1); + /* int len = OF_GET_ARG(2); */ + int c; + unsigned char ch; + + /* TODO: check handle! This just reads chars from the console! */ + /* TODO: This is blocking! */ + + c = console_readchar(cpu->machine->main_console_handle); + ch = c; + if (!cpu->memory_rw(cpu, cpu->mem, ptr, &ch, 1, MEM_WRITE, + CACHE_DATA | NO_EXCEPTIONS)) { + fatal("[ of: TODO: read: memory_rw() error ]\n"); + exit(1); + } + + store_32bit_word(cpu, base + retofs, c == -1? 0 : 1); + return c == -1? -1 : 0; +} + + +OF_SERVICE(write) +{ + /* int handle = OF_GET_ARG(0); */ + uint64_t ptr = OF_GET_ARG(1); + int n_written = 0, i, len = OF_GET_ARG(2); + + /* TODO: check handle! This just dumps the data to the console! */ + + for (i=0; imemory_rw(cpu, cpu->mem, ptr + i, &ch, + 1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) { + fatal("[ of: TODO: write: memory_rw() error ]\n"); + exit(1); + } + if (ch != 7) + console_putchar(cpu->machine->main_console_handle, ch); + n_written ++; + } + + store_32bit_word(cpu, base + retofs, n_written); + return 0; +} + + +/*****************************************************************************/ + + +/* + * of_get_unused_device_handle(): + * + * Returns an unused device handle number (1 or higher). + */ +static int of_get_unused_device_handle(struct of_data *of_data) +{ + int max_handle = 0; + struct of_device *od = of_data->of_devices; + + while (od != NULL) { + if (od->handle > max_handle) + max_handle = od->handle; + od = od->next; + } + + return max_handle + 1; +} + + +/* + * of_add_device(): + * + * Adds a device. + */ +static struct of_device *of_add_device(struct of_data *of_data, const char *name, + const char *parentname) +{ + struct of_device *od; + + CHECK_ALLOCATION(od = (struct of_device *) malloc(sizeof(struct of_device))); + memset(od, 0, sizeof(struct of_device)); + + CHECK_ALLOCATION(od->name = strdup(name)); + + od->handle = of_get_unused_device_handle(of_data); + od->parent = find_device_handle(of_data, parentname); + if (od->parent < 0) { + fatal("of_add_device(): adding '%s' to parent '%s' failed: " + "parent not found!\n", name, parentname); + exit(1); + } + + od->next = of_data->of_devices; + of_data->of_devices = od; + + return od; +} + + +/* + * of_add_prop(): + * + * Adds a property to a device. + */ +static void of_add_prop(struct of_data *of_data, const char *devname, + const char *propname, unsigned char *data, uint32_t len, int flags) +{ + struct of_device_property *pr; + struct of_device *od = of_data->of_devices; + int h = find_device_handle(of_data, devname); + + CHECK_ALLOCATION(pr = (struct of_device_property *) malloc(sizeof(struct of_device_property))); + memset(pr, 0, sizeof(struct of_device_property)); + + OF_FIND(od, od->handle == h); + if (od == NULL) { + fatal("of_add_prop(): device '%s' not registered\n", devname); + exit(1); + } + + CHECK_ALLOCATION(pr->name = strdup(propname)); + pr->data = data; + pr->len = len; + pr->flags = flags; + + pr->next = od->properties; + od->properties = pr; +} + + +/* + * of_add_service(): + * + * Adds a service. + */ +static void of_add_service(struct of_data *of_data, const char *name, + int (*f)(OF_SERVICE_ARGS), int n_args, int n_ret_args) +{ + struct of_service *os; + + CHECK_ALLOCATION(os = (struct of_service *) malloc(sizeof(struct of_service))); + memset(os, 0, sizeof(struct of_service)); + + CHECK_ALLOCATION(os->name = strdup(name)); + + os->f = f; + os->n_args = n_args; + os->n_ret_args = n_ret_args; + + os->next = of_data->of_services; + of_data->of_services = os; +} + + +/* + * of_dump_devices(): + * + * Debug dump helper. + */ +static void of_dump_devices(struct of_data *ofd, int parent) +{ + struct of_device *od = ofd->of_devices; + + while (od != NULL) { + struct of_device_property *pr = od->properties; + if (od->parent != parent) { + od = od->next; + continue; + } + + debug("\"%s\"", od->name); + debug(" (handle %i)\n", od->handle); + debug_indentation(1); + + while (pr != NULL) { + debug("(%s: ", pr->name); + if (pr->flags == OF_PROP_STRING) + debug("\"%s\"", pr->data); + else + debug("%i bytes", pr->len); + debug(")\n"); + pr = pr->next; + } + + of_dump_devices(ofd, od->handle); + debug_indentation(-1); + od = od->next; + } +} + + +/* + * of_dump_all(): + * + * Debug dump. + */ +static void of_dump_all(struct of_data *ofd) +{ + struct of_service *os; + + debug("openfirmware debug dump:\n"); + debug_indentation(1); + + /* Devices: */ + of_dump_devices(ofd, 0); + + /* Services: */ + os = ofd->of_services; + while (os != NULL) { + debug("service '%s'", os->name); + if (os->n_ret_args > 0 || os->n_args > 0) { + debug(" ("); + if (os->n_args > 0) { + debug("%i arg%s", os->n_args, + os->n_args > 1? "s" : ""); + if (os->n_ret_args > 0) + debug(", "); + } + if (os->n_ret_args > 0) + debug("%i return value%s", os->n_ret_args, + os->n_ret_args > 1? "s" : ""); + debug(")"); + } + debug("\n"); + os = os->next; + } + + debug_indentation(-1); +} + + +/* + * of_add_prop_int32(): + * + * Helper function. + */ +static void of_add_prop_int32(struct of_data *ofd, + const char *devname, const char *propname, uint32_t x) +{ + unsigned char *p; + + CHECK_ALLOCATION(p = (unsigned char *) malloc(sizeof(int32_t))); + + of_store_32bit_in_host(p, x); + of_add_prop(ofd, devname, propname, p, sizeof(int32_t), + OF_PROP_INT); +} + + +/* + * of_add_prop_str(): + * + * Helper function. + */ +static void of_add_prop_str(struct machine *machine, struct of_data *ofd, + const char *devname, const char *propname, const char *data) +{ + char *p; + + CHECK_ALLOCATION(p = strdup(data)); + + of_add_prop(ofd, devname, propname, (unsigned char *)p, strlen(p) + 1, + OF_PROP_STRING); +} + + +/* + * of_emul_init_isa(): + */ +void of_emul_init_isa(struct machine *machine) +{ + struct of_data *ofd = machine->md.of_data; + unsigned char *isa_ranges; + + of_add_device(ofd, "isa", "/"); + + CHECK_ALLOCATION(isa_ranges = (unsigned char *) malloc(32)); + memset(isa_ranges, 0, 32); + + /* 2 *: isa_phys_hi, isa_phys_lo, parent_phys_start, size */ + /* MEM space: */ + of_store_32bit_in_host(isa_ranges + 0, 0); + of_store_32bit_in_host(isa_ranges + 4, 0xc0000000); + /* I/O space: low bit if isa_phys_hi set */ + of_store_32bit_in_host(isa_ranges + 16, 1); + of_store_32bit_in_host(isa_ranges + 20, 0xd0000000); + + of_add_prop(ofd, "/isa", "ranges", isa_ranges, 32, 0); +} + + +/* + * of_emul_init_adb(): + */ +void of_emul_init_adb(struct machine *machine) +{ + struct of_data *ofd = machine->md.of_data; + unsigned char *adb_interrupts, *adb_reg; + + CHECK_ALLOCATION(adb_interrupts = (unsigned char *) malloc(4 * sizeof(uint32_t))); + CHECK_ALLOCATION(adb_reg = (unsigned char *) malloc(8 * sizeof(uint32_t))); + + of_add_device(ofd, "adb", "/bandit/gc"); + of_add_prop_str(machine, ofd, "/bandit/gc/adb", "name", "via-cuda"); + of_store_32bit_in_host(adb_interrupts + 0, 25); + of_store_32bit_in_host(adb_interrupts + 4, 0); + of_store_32bit_in_host(adb_interrupts + 8, 0); + of_store_32bit_in_host(adb_interrupts + 12, 0); + of_add_prop(ofd, "/bandit/gc/adb", "interrupts", adb_interrupts, + 4*sizeof(uint32_t), 0); + of_store_32bit_in_host(adb_reg + 0, 0x16000); + of_store_32bit_in_host(adb_reg + 4, 0x2000); + of_store_32bit_in_host(adb_reg + 8, 0); + of_store_32bit_in_host(adb_reg + 12, 0); + of_store_32bit_in_host(adb_reg + 16, 0); + of_store_32bit_in_host(adb_reg + 20, 0); + of_store_32bit_in_host(adb_reg + 24, 0); + of_store_32bit_in_host(adb_reg + 28, 0); + of_add_prop(ofd, "/bandit/gc/adb", "reg", adb_reg, + 8*sizeof(uint32_t), 0); +} + + +/* + * of_emul_init_zs(): + */ +void of_emul_init_zs(struct machine *machine) +{ + struct of_data *ofd = machine->md.of_data; + unsigned char *zs_interrupts, *zs_reg; + + CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); + + /* The controller: */ + of_add_device(ofd, "zs", "/bandit/gc"); + of_add_prop_str(machine, ofd, "/bandit/gc/zs", "device_type", "serial"); + of_add_prop_str(machine, ofd, "/bandit/gc/zs", "name", "escc"); + of_store_32bit_in_host(zs_reg + 0, 0x13000); + of_store_32bit_in_host(zs_reg + 4, 0x40); + of_store_32bit_in_host(zs_reg + 8, 0x100); + of_store_32bit_in_host(zs_reg + 12, 0x100); + of_store_32bit_in_host(zs_reg + 16, 0x200); + of_store_32bit_in_host(zs_reg + 20, 0x100); + of_add_prop(ofd, "/bandit/gc/zs", "reg", zs_reg, 6*sizeof(uint32_t), 0); + + /* Port 1: */ + CHECK_ALLOCATION(zs_interrupts = (unsigned char *) malloc(3 * sizeof(uint32_t))); + CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); + + of_add_device(ofd, "zstty1", "/bandit/gc/zs"); + of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty1", "name", "ch-a"); + of_store_32bit_in_host(zs_interrupts + 0, 16); + of_store_32bit_in_host(zs_interrupts + 4, 0); + of_store_32bit_in_host(zs_interrupts + 8, 0); + of_add_prop(ofd, "/bandit/gc/zs/zstty1", "interrupts", zs_interrupts, + 3*sizeof(uint32_t), 0); + of_store_32bit_in_host(zs_reg + 0, 0x13800); + of_store_32bit_in_host(zs_reg + 4, 0x100); + of_store_32bit_in_host(zs_reg + 8, 0x100); + of_store_32bit_in_host(zs_reg + 12, 0x100); + of_store_32bit_in_host(zs_reg + 16, 0x200); + of_store_32bit_in_host(zs_reg + 20, 0x100); + of_add_prop(ofd, "/bandit/gc/zs/zstty1", + "reg", zs_reg, 6*sizeof(uint32_t), 0); + + /* Port 0: */ + CHECK_ALLOCATION(zs_interrupts = (unsigned char *) malloc(3 * sizeof(uint32_t))); + CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); + + of_add_device(ofd, "zstty0", "/bandit/gc/zs"); + of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty0", "name", "ch-b"); + of_store_32bit_in_host(zs_interrupts + 0, 15); + of_store_32bit_in_host(zs_interrupts + 4, 0); + of_store_32bit_in_host(zs_interrupts + 8, 0); + of_add_prop(ofd, "/bandit/gc/zs/zstty0", "interrupts", zs_interrupts, + 3*sizeof(uint32_t), 0); + of_store_32bit_in_host(zs_reg + 0, 0x13400); + of_store_32bit_in_host(zs_reg + 4, 0x100); + of_store_32bit_in_host(zs_reg + 8, 0x100); + of_store_32bit_in_host(zs_reg + 12, 0x100); + of_store_32bit_in_host(zs_reg + 16, 0x200); + of_store_32bit_in_host(zs_reg + 20, 0x100); + of_add_prop(ofd, "/bandit/gc/zs/zstty0", + "reg", zs_reg, 6*sizeof(uint32_t), 0); +} + + +/* + * of_emul_init_uninorth(): + */ +void of_emul_init_uninorth(struct machine *machine) +{ + struct of_data *ofd = machine->md.of_data; + unsigned char *uninorth_reg, *uninorth_bus_range, *uninorth_ranges; + unsigned char *macio_aa, *ata_interrupts, *ata_reg; + struct of_device *ic; + const char *n = "pci@e2000000"; + const char *macio = "mac-io"; + + of_add_device(ofd, n, "/"); + of_add_prop_str(machine, ofd, n, "name", "pci"); + of_add_prop_str(machine, ofd, n, "device_type", "pci"); + of_add_prop_str(machine, ofd, n, "compatible", "uni-north"); + + CHECK_ALLOCATION(uninorth_reg = (unsigned char *) malloc(2 * sizeof(uint32_t))); + CHECK_ALLOCATION(uninorth_bus_range = (unsigned char *) malloc(2 * sizeof(uint32_t))); + CHECK_ALLOCATION(uninorth_ranges = (unsigned char *) malloc(12 * sizeof(uint32_t))); + CHECK_ALLOCATION(macio_aa = (unsigned char *) malloc(5 * sizeof(uint32_t))); + CHECK_ALLOCATION(ata_interrupts = (unsigned char *) malloc(6 * sizeof(uint32_t))); + CHECK_ALLOCATION(ata_reg = (unsigned char *) malloc(8 * sizeof(uint32_t))); + + of_store_32bit_in_host(uninorth_reg + 0, 0xe2000000); + of_store_32bit_in_host(uninorth_reg + 4, 0); /* not used? */ + of_add_prop(ofd, n, "reg", uninorth_reg, 2*sizeof(uint32_t), 0); + + of_store_32bit_in_host(uninorth_bus_range + 0, 0); + of_store_32bit_in_host(uninorth_bus_range + 4, 0); + of_add_prop(ofd, n, "bus-range", uninorth_bus_range, + 2*sizeof(uint32_t), 0); + + /* MEM: */ + of_store_32bit_in_host(uninorth_ranges + 0, 0x02000000); + of_store_32bit_in_host(uninorth_ranges + 4, 0); + of_store_32bit_in_host(uninorth_ranges + 8, 0); + of_store_32bit_in_host(uninorth_ranges + 12, 0xd0000000); + of_store_32bit_in_host(uninorth_ranges + 16, 0); + of_store_32bit_in_host(uninorth_ranges + 20, 0x04000000); + /* IO: */ + of_store_32bit_in_host(uninorth_ranges + 24, 0x01000000); + of_store_32bit_in_host(uninorth_ranges + 28, 0); + of_store_32bit_in_host(uninorth_ranges + 32, 0); + of_store_32bit_in_host(uninorth_ranges + 36, 0xe2000000); + of_store_32bit_in_host(uninorth_ranges + 40, 0); + of_store_32bit_in_host(uninorth_ranges + 44, 0x01000000); + of_add_prop(ofd, n, "ranges", uninorth_ranges, + 12*sizeof(uint32_t), 0); + + ic = of_add_device(ofd, macio, "/"); + memset(macio_aa, 0, 20); + of_store_32bit_in_host(macio_aa + 0, 15 << 11); /* pci tag */ + of_store_32bit_in_host(macio_aa + 8, 0xf3000000); + of_add_prop(ofd, macio, "assigned-addresses", macio_aa, + 5*sizeof(uint32_t), 0); +/* of_add_prop(ofd, n, "assigned-addresses", macio_aa, + 5*sizeof(uint32_t), 0); */ + of_add_prop_int32(ofd, "/chosen", "interrupt-controller", ic->handle); + + of_add_device(ofd, "bandit", "/"); + of_add_device(ofd, "gc", "/bandit"); + of_add_prop(ofd, "/bandit/gc", "assigned-addresses", macio_aa, + 5*sizeof(uint32_t), 0); + + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || + diskimage_exist(machine, 1, DISKIMAGE_IDE)) { + char tmpstr[400]; + of_add_device(ofd, "ata", "/bandit/gc"); + of_add_prop_str(machine, ofd, "/bandit/gc/ata", "name", "ata"); + of_add_prop_str(machine, ofd, "/bandit/gc/ata", "compatible", + "heathrow-ata"); + of_store_32bit_in_host(ata_interrupts + 0, 13); + of_store_32bit_in_host(ata_interrupts + 4, 0); + of_store_32bit_in_host(ata_interrupts + 8, 0); + of_store_32bit_in_host(ata_interrupts + 12, 0); + of_store_32bit_in_host(ata_interrupts + 16, 0); + of_store_32bit_in_host(ata_interrupts + 20, 0); + of_add_prop(ofd, "/bandit/gc/ata", "interrupts", ata_interrupts, + 6*sizeof(uint32_t), 0); + of_store_32bit_in_host(ata_reg + 0, 0x20000); + of_store_32bit_in_host(ata_reg + 4, 0); + of_store_32bit_in_host(ata_reg + 8, 0x21000); + of_store_32bit_in_host(ata_reg + 12, 0x22000); + of_store_32bit_in_host(ata_reg + 16, 0); + of_store_32bit_in_host(ata_reg + 20, 0); + of_store_32bit_in_host(ata_reg + 24, 0); + of_store_32bit_in_host(ata_reg + 28, 0); + of_add_prop(ofd, "/bandit/gc/ata", "reg", ata_reg, + 8*sizeof(uint32_t), 0); + + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0xf3020000 " + "irq=%s.cpu[%i].gc.lo.21 addr_mult=0x10", machine->path, + machine->bootstrap_cpu); + device_add(machine, tmpstr); + } +} + + +/* + * of_emul_init(): + * + * This function creates an OpenFirmware emulation instance. + */ +struct of_data *of_emul_init(struct machine *machine, struct vfb_data *vfb_data, + uint64_t fb_addr, int fb_xsize, int fb_ysize) +{ + unsigned char *memory_reg, *memory_av; + unsigned char *root_address_cells, *root_size_cells; + unsigned char *zs_assigned_addresses; + struct of_device *memory_dev, *mmu, *devstdout, *devstdin; + struct of_data *ofd; + int i; + + CHECK_ALLOCATION(ofd = (struct of_data *) malloc(sizeof(struct of_data))); + memset(ofd, 0, sizeof(struct of_data)); + + ofd->vfb_data = vfb_data; + + /* Devices: */ + + /* Root = device 1 */ + of_add_device(ofd, "", ""); + of_add_prop_str(machine, ofd, "/", "model", "GXemul OpenFirmware machine"); + + CHECK_ALLOCATION(root_address_cells = (unsigned char *) malloc(1 * sizeof(uint32_t))); + of_store_32bit_in_host(root_address_cells, 0); + of_add_prop(ofd, "/", "#address-cells", root_address_cells, 1 * sizeof(uint32_t), 0); + + CHECK_ALLOCATION(root_size_cells = (unsigned char *) malloc(1 * sizeof(uint32_t))); + of_store_32bit_in_host(root_size_cells, 0); + of_add_prop(ofd, "/", "#size-cells", root_size_cells, 1 * sizeof(uint32_t), 0); + + of_add_device(ofd, "io", "/"); + devstdin = of_add_device(ofd, "stdin", "/io"); + devstdout = of_add_device(ofd, "stdout", "/io"); + + if (machine->x11_md.in_use) { + fatal("!\n! TODO: keyboard + framebuffer for MacPPC\n!\n"); + + of_add_prop_str(machine, ofd, "/io/stdin", "name", + "keyboard"); + of_add_prop_str(machine, ofd, "/io", "name", "adb"); + + of_add_prop_str(machine, ofd, "/io/stdout", "device_type", + "display"); + of_add_prop_int32(ofd, "/io/stdout", "width", fb_xsize); + of_add_prop_int32(ofd, "/io/stdout", "height", fb_ysize); + of_add_prop_int32(ofd, "/io/stdout", "linebytes", fb_xsize * 1); + of_add_prop_int32(ofd, "/io/stdout", "depth", 8); + of_add_prop_int32(ofd, "/io/stdout", "address", fb_addr); + } else { + CHECK_ALLOCATION(zs_assigned_addresses = (unsigned char *) malloc(12)); + memset(zs_assigned_addresses, 0, 12); + + of_add_prop_str(machine, ofd, "/io/stdin", "name", "ch-b"); + of_add_prop_str(machine, ofd, "/io/stdin", "device_type", + "serial"); + of_add_prop_int32(ofd, "/io/stdin", "reg", 0xf3013000); + of_add_prop(ofd, "/io/stdin", "assigned-addresses", + zs_assigned_addresses, 12, 0); + + of_add_prop_str(machine, ofd, "/io/stdout", "device_type", + "serial"); + } + + of_add_device(ofd, "cpus", "/"); + for (i=0; incpus; i++) { + char tmp[50]; + snprintf(tmp, sizeof(tmp), "@%x", i); + of_add_device(ofd, tmp, "/cpus"); + snprintf(tmp, sizeof(tmp), "/cpus/@%x", i); + of_add_prop_str(machine, ofd, tmp, "device_type", "cpu"); + of_add_prop_int32(ofd, tmp, "timebase-frequency", + machine->emulated_hz / 4); + of_add_prop_int32(ofd, tmp, "clock-frequency", + machine->emulated_hz); + of_add_prop_int32(ofd, tmp, "reg", i); + } + + mmu = of_add_device(ofd, "mmu", "/"); + + /* TODO: */ + of_add_prop(ofd, "/mmu", "translations", NULL, 0, 0); + + of_add_device(ofd, "chosen", "/"); + of_add_prop_int32(ofd, "/chosen", "mmu", mmu->handle); + of_add_prop_int32(ofd, "/chosen", "stdin", devstdin->handle); + of_add_prop_int32(ofd, "/chosen", "stdout", devstdout->handle); + + memory_dev = of_add_device(ofd, "memory", "/"); + CHECK_ALLOCATION(memory_reg = (unsigned char *) malloc(2 * sizeof(uint32_t))); + CHECK_ALLOCATION(memory_av = (unsigned char *) malloc(2 * sizeof(uint32_t))); + + of_store_32bit_in_host(memory_reg + 0, 0); + of_store_32bit_in_host(memory_reg + 4, machine->physical_ram_in_mb<<20); + of_store_32bit_in_host(memory_av + 0, 10 << 20); + of_store_32bit_in_host(memory_av + 4, (machine->physical_ram_in_mb - 10) << 20); + of_add_prop(ofd, "/memory", "reg", memory_reg, 2 * sizeof(uint32_t), 0); + of_add_prop(ofd, "/memory", "available", memory_av, 2*sizeof(uint32_t),0); + of_add_prop_str(machine, ofd, "/memory", "name", "memory"); + of_add_prop_str(machine, ofd, "/memory","device_type","memory"/*?*/); + + of_add_prop_int32(ofd, "/chosen", "memory", memory_dev->handle); + + /* Services: */ + of_add_service(ofd, "call-method", of__call_method_2_2, 2, 2); + of_add_service(ofd, "call-method", of__call_method_3_4, 3, 4); + of_add_service(ofd, "call-method", of__call_method_5_2, 5, 2); + of_add_service(ofd, "call-method", of__call_method_6_1, 6, 1); + of_add_service(ofd, "call-method", of__call_method_6_2, 6, 2); + of_add_service(ofd, "child", of__child, 1, 1); + of_add_service(ofd, "claim", of__claim, 3, 1); + of_add_service(ofd, "exit", of__exit, 0, 0); + of_add_service(ofd, "finddevice", of__finddevice, 1, 1); + of_add_service(ofd, "getprop", of__getprop, 4, 1); + of_add_service(ofd, "getproplen", of__getproplen, 2, 1); + of_add_service(ofd, "instance-to-package", + of__instance_to_package, 1, 1); + of_add_service(ofd, "interpret", of__interpret_1, 1, 1); + of_add_service(ofd, "interpret", of__interpret_2, 1, 2); + of_add_service(ofd, "package-to-path", of__package_to_path, 3, 1); + of_add_service(ofd, "parent", of__parent, 1, 1); + of_add_service(ofd, "peer", of__peer, 1, 1); + of_add_service(ofd, "open", of__open, 1, 1); + of_add_service(ofd, "read", of__read, 3, 1); + of_add_service(ofd, "write", of__write, 3, 1); + + if (verbose >= 2) + of_dump_all(ofd); + + machine->md.of_data = ofd; + + return ofd; +} + + +/* + * of_emul(): + * + * OpenFirmware call emulation. + */ +int of_emul(struct cpu *cpu) +{ + int i, nargs, nret, ofs, retval = 0; + char service[50]; + char *arg[OF_N_MAX_ARGS]; + uint64_t base, ptr; + struct of_service *os; + struct of_data *of_data = cpu->machine->md.of_data; + + if (of_data == NULL) { + fatal("of_emul(): no of_data struct?\n"); + exit(1); + } + + /* + * The first argument register points to "prom_args": + * + * char *service; (probably 32 bit) + * int nargs; + * int nret; + * char *args[10]; + */ + + switch (cpu->cpu_family->arch) { + case ARCH_ARM: + base = cpu->cd.arm.r[0]; + break; + case ARCH_PPC: + base = cpu->cd.ppc.gpr[3]; + break; + default:fatal("of_emul(): unimplemented arch (TODO)\n"); + exit(1); + } + + /* TODO: how about 64-bit OpenFirmware? */ + ptr = load_32bit_word(cpu, base); + nargs = load_32bit_word(cpu, base + 4); + nret = load_32bit_word(cpu, base + 8); + + readstr(cpu, ptr, service, sizeof(service)); + + debug("[ of: %s(", service); + ofs = 12; + for (i=0; i 0) + debug(", "); + if (i >= OF_N_MAX_ARGS) { + fatal("TOO MANY ARGS!"); + continue; + } + + ptr = load_32bit_word(cpu, base + ofs); + + CHECK_ALLOCATION(arg[i] = (char *) malloc(OF_ARG_MAX_LEN + 1)); + memset(arg[i], 0, OF_ARG_MAX_LEN + 1); + + x = ptr; + if (x > -256 && x < 256) { + debug("%i", x); + } else { + readstr(cpu, ptr, arg[i], OF_ARG_MAX_LEN); + if (arg[i][0]) + debug("\"%s\"", arg[i]); + else + debug("0x%x", x); + } + ofs += sizeof(uint32_t); + } + debug(") ]\n"); + + /* Note: base + ofs points to the first return slot. */ + + os = of_data->of_services; + while (os != NULL) { + if (strcmp(service, os->name) == 0 && + nargs == os->n_args && nret == os->n_ret_args) { + retval = os->f(cpu, arg, base, ofs); + break; + } + os = os->next; + } + + if (os == NULL) { + quiet_mode = 0; + cpu_register_dump(cpu->machine, cpu, 1, 0); + printf("\n"); + fatal("[ of: unimplemented service \"%s\" with %i input " + "args and %i output values ]\n", service, nargs, nret); + cpu->running = 0; + exit(1); + } + + for (i=0; icpu_family->arch) { + case ARCH_ARM: + cpu->cd.arm.r[0] = retval; + break; + case ARCH_PPC: + cpu->cd.ppc.gpr[3] = retval; + break; + default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n"); + exit(1); + } + + return 1; +} + diff -Nru gxemul-0.6.2/src/promemul/of.cc gxemul-0.7.0+dfsg/src/promemul/of.cc --- gxemul-0.6.2/src/promemul/of.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/of.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,1188 +0,0 @@ -/* - * Copyright (C) 2005-2012 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: OpenFirmware emulation - * - * NOTE: This module is/was a quick hack, with the purpose of getting - * NetBSD/macppc to boot. If anything else boots using this hackish - * implementation of OpenFirmware, then that is a bonus. - * - ****************************************************************************** - * - * NOTE: OpenFirmware is used on quite a variety of different hardware archs, - * at least POWER/PowerPC, ARM, and SPARC, so the code in this module - * must always remain architecture agnostic. - * - * NOTE: Some things, e.g. 32-bit integers as returned by the "getprop" - * service, are always fixed to big-endian. (According to the standard.) - * - * TODO: o) 64-bit OpenFirmware? - * o) More devices... - */ - -#include -#include -#include -#include - -#define OF_C - -#include "console.h" -#include "cpu.h" -#include "device.h" -#include "devices.h" -#include "diskimage.h" -#include "machine.h" -#include "memory.h" -#include "misc.h" -#include "of.h" - - -/* #define debug fatal */ - -extern int quiet_mode; -extern int verbose; - - -/* - * readstr(): - * - * Helper function to read a string from emulated memory. - */ -static void readstr(struct cpu *cpu, uint64_t addr, char *strbuf, - int bufsize) -{ - int i; - for (i=0; imemory_rw(cpu, cpu->mem, addr + i, - &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); - strbuf[i] = '\0'; - if (ch >= 1 && ch < 32) - ch = 0; - strbuf[i] = ch; - if (strbuf[i] == '\0') - break; - } - - strbuf[bufsize - 1] = '\0'; -} - - -/* - * of_store_32bit_in_host(): - * - * Store big-endian. OpenFirmware properties returned by getprop etc are - * always big-endian, even on little-endian machines. - */ -static void of_store_32bit_in_host(unsigned char *d, uint32_t x) -{ - d[0] = x >> 24; d[1] = x >> 16; - d[2] = x >> 8; d[3] = x; -} - - -/* - * find_device_handle(): - * - * name may consist of multiple names, separated with slashes. - */ -static int find_device_handle(struct of_data *ofd, const char *name) -{ - int handle = 1, cur_parent = 1; - - if (name[0] == 0) - return 0; - - for (;;) { - struct of_device *od = ofd->of_devices; - char tmp[200]; - int i; - - while (name[0] == '/') - name++; - if (name[0] == '\0') - break; - snprintf(tmp, sizeof(tmp), "%s", name); - i = 0; - while (tmp[i] != '\0' && tmp[i] != '/') - i++; - tmp[i] = '\0'; - - OF_FIND(od, strcmp(od->name, tmp) == 0 && - od->parent == cur_parent); - if (od == NULL) - return -1; - - handle = cur_parent = od->handle; - name += strlen(tmp); - } - - return handle; -} - - -/*****************************************************************************/ - - -OF_SERVICE(call_method_2_2) -{ - fatal("[ of: call_method_2_2('%s'): TODO ]\n", arg[0]); - return -1; -} - - -OF_SERVICE(call_method_3_4) -{ - fatal("[ of: call_method_3_4('%s'): TODO ]\n", arg[0]); - return -1; -} - - -OF_SERVICE(call_method_5_2) -{ - if (strcmp(arg[0], "set-colors") == 0) { - /* Used by OpenBSD/macppc: */ - struct vfb_data *v = cpu->machine->md.of_data->vfb_data; - int color = OF_GET_ARG(3); - uint64_t ptr = OF_GET_ARG(4); - unsigned char rgb[3]; - cpu->memory_rw(cpu, cpu->mem, ptr, rgb, 3, MEM_READ, - CACHE_DATA | NO_EXCEPTIONS); - if (v != NULL) { - memcpy(v->rgb_palette + 3 * color, rgb, 3); - v->update_x1 = v->update_y1 = 0; - v->update_x2 = v->xsize - 1; - v->update_y2 = v->ysize - 1; - } - } else { - fatal("[ of: call_method_5_2('%s'): TODO ]\n", arg[0]); - return -1; - } - return 0; -} - - -OF_SERVICE(call_method_6_1) -{ - fatal("[ of: call_method_6_1('%s'): TODO ]\n", arg[0]); - return -1; -} - - -OF_SERVICE(call_method_6_2) -{ - fatal("[ of: call_method_6_2('%s'): TODO ]\n", arg[0]); - return -1; -} - - -OF_SERVICE(child) -{ - struct of_device *od = cpu->machine->md.of_data->of_devices; - int handle = OF_GET_ARG(0); - OF_FIND(od, od->parent == handle); - store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->handle); - return 0; -} - - -OF_SERVICE(claim) -{ - // Arguments: virtualaddr, size, alignment - // Returns: pointer to claimed memory - - // TODO: This is just a dummy. - fatal("[ of: claim(0x%x,0x%x,0x%x): TODO ]\n", - OF_GET_ARG(0), OF_GET_ARG(1), OF_GET_ARG(2)); - - store_32bit_word(cpu, base + retofs, OF_GET_ARG(0)); - return 0; -} - - -OF_SERVICE(exit) -{ - cpu->running = 0; - return 0; -} - - -OF_SERVICE(finddevice) -{ - int h = find_device_handle(cpu->machine->md.of_data, arg[0]); - store_32bit_word(cpu, base + retofs, h); - return h>0? 0 : -1; -} - - -OF_SERVICE(getprop) -{ - struct of_device *od = cpu->machine->md.of_data->of_devices; - struct of_device_property *pr; - int handle = OF_GET_ARG(0), i, len_returned = 0; - uint64_t buf = OF_GET_ARG(2); - uint64_t max = OF_GET_ARG(3); - - OF_FIND(od, od->handle == handle); - if (od == NULL) { - fatal("[ of: WARNING: getprop handle=%i; no such handle ]\n", - handle); - return -1; - } - - pr = od->properties; - OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); - if (pr == NULL) { - fatal("[ of: WARNING: getprop: no property '%s' at handle" - " %i (device '%s') ]\n", arg[1], handle, od->name); - return -1; - } - - if (pr->data == NULL) { - fatal("[ of: WARNING: property '%s' of '%s' has no data! ]\n", - arg[1], od->name); - goto ret; - } - - /* Return the property into emulated RAM: */ - len_returned = pr->len <= max? pr->len : max; - - for (i=0; imemory_rw(cpu, cpu->mem, buf + i, pr->data + i, - 1, MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS)) { - fatal("[ of: getprop memory_rw() error ]\n"); - exit(1); - } - } - -ret: - store_32bit_word(cpu, base + retofs, len_returned); - return 0; -} - - -OF_SERVICE(getproplen) -{ - struct of_device *od = cpu->machine->md.of_data->of_devices; - struct of_device_property *pr; - int handle = OF_GET_ARG(0); - - OF_FIND(od, od->handle == handle); - if (od == NULL) { - fatal("[ of: TODO: getproplen handle=%i; no such handle ]\n", - handle); - return -1; - } - - pr = od->properties; - OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); - if (pr == NULL) { - fatal("[ of: TODO: getproplen: no property '%s' at handle" - " %i (device '%s') ]\n", arg[1], handle, od->name); - return -1; - } - - store_32bit_word(cpu, base + retofs, pr->len); - return 0; -} - - -OF_SERVICE(instance_to_package) -{ - int handle = OF_GET_ARG(0); - /* TODO: actually do something here? :-) */ - store_32bit_word(cpu, base + retofs, handle); - return 0; -} - - -OF_SERVICE(interpret_1) -{ - if (strcmp(arg[0], "#lines 2 - to line#") == 0) { - } else { - fatal("[ of: interpret_1('%s'): TODO ]\n", arg[0]); - return -1; - } - return 0; -} - - -OF_SERVICE(interpret_2) -{ - store_32bit_word(cpu, base + retofs, 0); /* ? TODO */ - if (strcmp(arg[0], "#columns") == 0) { - store_32bit_word(cpu, base + retofs + 4, 80); - } else if (strcmp(arg[0], "#lines") == 0) { - store_32bit_word(cpu, base + retofs + 4, 40); - } else if (strcmp(arg[0], "char-height") == 0) { - store_32bit_word(cpu, base + retofs + 4, 15); - } else if (strcmp(arg[0], "char-width") == 0) { - store_32bit_word(cpu, base + retofs + 4, 10); - } else if (strcmp(arg[0], "line#") == 0) { - store_32bit_word(cpu, base + retofs + 4, 0); - } else if (strcmp(arg[0], "font-adr") == 0) { - store_32bit_word(cpu, base + retofs + 4, 0); - } else { - fatal("[ of: interpret_2('%s'): TODO ]\n", arg[0]); - return -1; - } - return 0; -} - - -OF_SERVICE(package_to_path) -{ - fatal("[ of: package-to-path: TODO ]\n"); - return -1; -} - - -OF_SERVICE(parent) -{ - struct of_device *od = cpu->machine->md.of_data->of_devices; - int handle = OF_GET_ARG(0); - OF_FIND(od, od->handle == handle); - store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->parent); - return 0; -} - - -OF_SERVICE(peer) -{ - struct of_device *od = cpu->machine->md.of_data->of_devices; - int handle = OF_GET_ARG(0), parent = 0, peer = 0, seen_self = 1; - - if (handle == 0) { - /* Return the handle of the root node (1): */ - store_32bit_word(cpu, base + retofs, 1); - return 0; - } - - OF_FIND(od, od->handle == handle); - if (od == NULL) { - fatal("[ of: TODO: peer(): can't find handle %i ]\n", handle); - exit(1); - } - parent = od->parent; - seen_self = 0; - - od = cpu->machine->md.of_data->of_devices; - - while (od != NULL) { - if (od->parent == parent) { - if (seen_self) { - peer = od->handle; - break; - } - if (od->handle == handle) - seen_self = 1; - } - od = od->next; - } - store_32bit_word(cpu, base + retofs, peer); - return 0; -} - - -OF_SERVICE(open) -{ - // TODO. - uint64_t ptr = OF_GET_ARG(0); - - string s; - - int i = 0; - while (true) { - unsigned char ch; - if (!cpu->memory_rw(cpu, cpu->mem, ptr + i, &ch, - 1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) { - fatal("[ of: TODO: write: memory_rw() error ]\n"); - exit(1); - } - - if (ch == 0) - break; - - s += ch; - ++ i; - } - - if (s != "") { - cout << "Unimplemented OF_SERVICE(open) with name: '" << s << "'\n"; - exit(1); - } - - return 0; -} - - -OF_SERVICE(read) -{ - /* int handle = OF_GET_ARG(0); */ - uint64_t ptr = OF_GET_ARG(1); - /* int len = OF_GET_ARG(2); */ - int c; - unsigned char ch; - - /* TODO: check handle! This just reads chars from the console! */ - /* TODO: This is blocking! */ - - c = console_readchar(cpu->machine->main_console_handle); - ch = c; - if (!cpu->memory_rw(cpu, cpu->mem, ptr, &ch, 1, MEM_WRITE, - CACHE_DATA | NO_EXCEPTIONS)) { - fatal("[ of: TODO: read: memory_rw() error ]\n"); - exit(1); - } - - store_32bit_word(cpu, base + retofs, c == -1? 0 : 1); - return c == -1? -1 : 0; -} - - -OF_SERVICE(write) -{ - /* int handle = OF_GET_ARG(0); */ - uint64_t ptr = OF_GET_ARG(1); - int n_written = 0, i, len = OF_GET_ARG(2); - - /* TODO: check handle! This just dumps the data to the console! */ - - for (i=0; imemory_rw(cpu, cpu->mem, ptr + i, &ch, - 1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) { - fatal("[ of: TODO: write: memory_rw() error ]\n"); - exit(1); - } - if (ch != 7) - console_putchar(cpu->machine->main_console_handle, ch); - n_written ++; - } - - store_32bit_word(cpu, base + retofs, n_written); - return 0; -} - - -/*****************************************************************************/ - - -/* - * of_get_unused_device_handle(): - * - * Returns an unused device handle number (1 or higher). - */ -static int of_get_unused_device_handle(struct of_data *of_data) -{ - int max_handle = 0; - struct of_device *od = of_data->of_devices; - - while (od != NULL) { - if (od->handle > max_handle) - max_handle = od->handle; - od = od->next; - } - - return max_handle + 1; -} - - -/* - * of_add_device(): - * - * Adds a device. - */ -static struct of_device *of_add_device(struct of_data *of_data, const char *name, - const char *parentname) -{ - struct of_device *od; - - CHECK_ALLOCATION(od = (struct of_device *) malloc(sizeof(struct of_device))); - memset(od, 0, sizeof(struct of_device)); - - CHECK_ALLOCATION(od->name = strdup(name)); - - od->handle = of_get_unused_device_handle(of_data); - od->parent = find_device_handle(of_data, parentname); - if (od->parent < 0) { - fatal("of_add_device(): adding '%s' to parent '%s' failed: " - "parent not found!\n", name, parentname); - exit(1); - } - - od->next = of_data->of_devices; - of_data->of_devices = od; - - return od; -} - - -/* - * of_add_prop(): - * - * Adds a property to a device. - */ -static void of_add_prop(struct of_data *of_data, const char *devname, - const char *propname, unsigned char *data, uint32_t len, int flags) -{ - struct of_device_property *pr; - struct of_device *od = of_data->of_devices; - int h = find_device_handle(of_data, devname); - - CHECK_ALLOCATION(pr = (struct of_device_property *) malloc(sizeof(struct of_device_property))); - memset(pr, 0, sizeof(struct of_device_property)); - - OF_FIND(od, od->handle == h); - if (od == NULL) { - fatal("of_add_prop(): device '%s' not registered\n", devname); - exit(1); - } - - CHECK_ALLOCATION(pr->name = strdup(propname)); - pr->data = data; - pr->len = len; - pr->flags = flags; - - pr->next = od->properties; - od->properties = pr; -} - - -/* - * of_add_service(): - * - * Adds a service. - */ -static void of_add_service(struct of_data *of_data, const char *name, - int (*f)(OF_SERVICE_ARGS), int n_args, int n_ret_args) -{ - struct of_service *os; - - CHECK_ALLOCATION(os = (struct of_service *) malloc(sizeof(struct of_service))); - memset(os, 0, sizeof(struct of_service)); - - CHECK_ALLOCATION(os->name = strdup(name)); - - os->f = f; - os->n_args = n_args; - os->n_ret_args = n_ret_args; - - os->next = of_data->of_services; - of_data->of_services = os; -} - - -/* - * of_dump_devices(): - * - * Debug dump helper. - */ -static void of_dump_devices(struct of_data *ofd, int parent) -{ - int iadd = DEBUG_INDENTATION; - struct of_device *od = ofd->of_devices; - - while (od != NULL) { - struct of_device_property *pr = od->properties; - if (od->parent != parent) { - od = od->next; - continue; - } - - debug("\"%s\"", od->name); - debug(" (handle %i)\n", od->handle); - debug_indentation(iadd); - - while (pr != NULL) { - debug("(%s: ", pr->name); - if (pr->flags == OF_PROP_STRING) - debug("\"%s\"", pr->data); - else - debug("%i bytes", pr->len); - debug(")\n"); - pr = pr->next; - } - - of_dump_devices(ofd, od->handle); - debug_indentation(-iadd); - od = od->next; - } -} - - -/* - * of_dump_all(): - * - * Debug dump. - */ -static void of_dump_all(struct of_data *ofd) -{ - int iadd = DEBUG_INDENTATION; - struct of_service *os; - - debug("openfirmware debug dump:\n"); - debug_indentation(iadd); - - /* Devices: */ - of_dump_devices(ofd, 0); - - /* Services: */ - os = ofd->of_services; - while (os != NULL) { - debug("service '%s'", os->name); - if (os->n_ret_args > 0 || os->n_args > 0) { - debug(" ("); - if (os->n_args > 0) { - debug("%i arg%s", os->n_args, - os->n_args > 1? "s" : ""); - if (os->n_ret_args > 0) - debug(", "); - } - if (os->n_ret_args > 0) - debug("%i return value%s", os->n_ret_args, - os->n_ret_args > 1? "s" : ""); - debug(")"); - } - debug("\n"); - os = os->next; - } - - debug_indentation(-iadd); -} - - -/* - * of_add_prop_int32(): - * - * Helper function. - */ -static void of_add_prop_int32(struct of_data *ofd, - const char *devname, const char *propname, uint32_t x) -{ - unsigned char *p; - - CHECK_ALLOCATION(p = (unsigned char *) malloc(sizeof(int32_t))); - - of_store_32bit_in_host(p, x); - of_add_prop(ofd, devname, propname, p, sizeof(int32_t), - OF_PROP_INT); -} - - -/* - * of_add_prop_str(): - * - * Helper function. - */ -static void of_add_prop_str(struct machine *machine, struct of_data *ofd, - const char *devname, const char *propname, const char *data) -{ - char *p; - - CHECK_ALLOCATION(p = strdup(data)); - - of_add_prop(ofd, devname, propname, (unsigned char *)p, strlen(p) + 1, - OF_PROP_STRING); -} - - -/* - * of_emul_init_isa(): - */ -void of_emul_init_isa(struct machine *machine) -{ - struct of_data *ofd = machine->md.of_data; - unsigned char *isa_ranges; - - of_add_device(ofd, "isa", "/"); - - CHECK_ALLOCATION(isa_ranges = (unsigned char *) malloc(32)); - memset(isa_ranges, 0, 32); - - /* 2 *: isa_phys_hi, isa_phys_lo, parent_phys_start, size */ - /* MEM space: */ - of_store_32bit_in_host(isa_ranges + 0, 0); - of_store_32bit_in_host(isa_ranges + 4, 0xc0000000); - /* I/O space: low bit if isa_phys_hi set */ - of_store_32bit_in_host(isa_ranges + 16, 1); - of_store_32bit_in_host(isa_ranges + 20, 0xd0000000); - - of_add_prop(ofd, "/isa", "ranges", isa_ranges, 32, 0); -} - - -/* - * of_emul_init_adb(): - */ -void of_emul_init_adb(struct machine *machine) -{ - struct of_data *ofd = machine->md.of_data; - unsigned char *adb_interrupts, *adb_reg; - - CHECK_ALLOCATION(adb_interrupts = (unsigned char *) malloc(4 * sizeof(uint32_t))); - CHECK_ALLOCATION(adb_reg = (unsigned char *) malloc(8 * sizeof(uint32_t))); - - of_add_device(ofd, "adb", "/bandit/gc"); - of_add_prop_str(machine, ofd, "/bandit/gc/adb", "name", "via-cuda"); - of_store_32bit_in_host(adb_interrupts + 0, 25); - of_store_32bit_in_host(adb_interrupts + 4, 0); - of_store_32bit_in_host(adb_interrupts + 8, 0); - of_store_32bit_in_host(adb_interrupts + 12, 0); - of_add_prop(ofd, "/bandit/gc/adb", "interrupts", adb_interrupts, - 4*sizeof(uint32_t), 0); - of_store_32bit_in_host(adb_reg + 0, 0x16000); - of_store_32bit_in_host(adb_reg + 4, 0x2000); - of_store_32bit_in_host(adb_reg + 8, 0); - of_store_32bit_in_host(adb_reg + 12, 0); - of_store_32bit_in_host(adb_reg + 16, 0); - of_store_32bit_in_host(adb_reg + 20, 0); - of_store_32bit_in_host(adb_reg + 24, 0); - of_store_32bit_in_host(adb_reg + 28, 0); - of_add_prop(ofd, "/bandit/gc/adb", "reg", adb_reg, - 8*sizeof(uint32_t), 0); -} - - -/* - * of_emul_init_zs(): - */ -void of_emul_init_zs(struct machine *machine) -{ - struct of_data *ofd = machine->md.of_data; - unsigned char *zs_interrupts, *zs_reg; - - CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); - - /* The controller: */ - of_add_device(ofd, "zs", "/bandit/gc"); - of_add_prop_str(machine, ofd, "/bandit/gc/zs", "device_type", "serial"); - of_add_prop_str(machine, ofd, "/bandit/gc/zs", "name", "escc"); - of_store_32bit_in_host(zs_reg + 0, 0x13000); - of_store_32bit_in_host(zs_reg + 4, 0x40); - of_store_32bit_in_host(zs_reg + 8, 0x100); - of_store_32bit_in_host(zs_reg + 12, 0x100); - of_store_32bit_in_host(zs_reg + 16, 0x200); - of_store_32bit_in_host(zs_reg + 20, 0x100); - of_add_prop(ofd, "/bandit/gc/zs", "reg", zs_reg, 6*sizeof(uint32_t), 0); - - /* Port 1: */ - CHECK_ALLOCATION(zs_interrupts = (unsigned char *) malloc(3 * sizeof(uint32_t))); - CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); - - of_add_device(ofd, "zstty1", "/bandit/gc/zs"); - of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty1", "name", "ch-a"); - of_store_32bit_in_host(zs_interrupts + 0, 16); - of_store_32bit_in_host(zs_interrupts + 4, 0); - of_store_32bit_in_host(zs_interrupts + 8, 0); - of_add_prop(ofd, "/bandit/gc/zs/zstty1", "interrupts", zs_interrupts, - 3*sizeof(uint32_t), 0); - of_store_32bit_in_host(zs_reg + 0, 0x13800); - of_store_32bit_in_host(zs_reg + 4, 0x100); - of_store_32bit_in_host(zs_reg + 8, 0x100); - of_store_32bit_in_host(zs_reg + 12, 0x100); - of_store_32bit_in_host(zs_reg + 16, 0x200); - of_store_32bit_in_host(zs_reg + 20, 0x100); - of_add_prop(ofd, "/bandit/gc/zs/zstty1", - "reg", zs_reg, 6*sizeof(uint32_t), 0); - - /* Port 0: */ - CHECK_ALLOCATION(zs_interrupts = (unsigned char *) malloc(3 * sizeof(uint32_t))); - CHECK_ALLOCATION(zs_reg = (unsigned char *) malloc(6 * sizeof(uint32_t))); - - of_add_device(ofd, "zstty0", "/bandit/gc/zs"); - of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty0", "name", "ch-b"); - of_store_32bit_in_host(zs_interrupts + 0, 15); - of_store_32bit_in_host(zs_interrupts + 4, 0); - of_store_32bit_in_host(zs_interrupts + 8, 0); - of_add_prop(ofd, "/bandit/gc/zs/zstty0", "interrupts", zs_interrupts, - 3*sizeof(uint32_t), 0); - of_store_32bit_in_host(zs_reg + 0, 0x13400); - of_store_32bit_in_host(zs_reg + 4, 0x100); - of_store_32bit_in_host(zs_reg + 8, 0x100); - of_store_32bit_in_host(zs_reg + 12, 0x100); - of_store_32bit_in_host(zs_reg + 16, 0x200); - of_store_32bit_in_host(zs_reg + 20, 0x100); - of_add_prop(ofd, "/bandit/gc/zs/zstty0", - "reg", zs_reg, 6*sizeof(uint32_t), 0); -} - - -/* - * of_emul_init_uninorth(): - */ -void of_emul_init_uninorth(struct machine *machine) -{ - struct of_data *ofd = machine->md.of_data; - unsigned char *uninorth_reg, *uninorth_bus_range, *uninorth_ranges; - unsigned char *macio_aa, *ata_interrupts, *ata_reg; - struct of_device *ic; - const char *n = "pci@e2000000"; - const char *macio = "mac-io"; - - of_add_device(ofd, n, "/"); - of_add_prop_str(machine, ofd, n, "name", "pci"); - of_add_prop_str(machine, ofd, n, "device_type", "pci"); - of_add_prop_str(machine, ofd, n, "compatible", "uni-north"); - - CHECK_ALLOCATION(uninorth_reg = (unsigned char *) malloc(2 * sizeof(uint32_t))); - CHECK_ALLOCATION(uninorth_bus_range = (unsigned char *) malloc(2 * sizeof(uint32_t))); - CHECK_ALLOCATION(uninorth_ranges = (unsigned char *) malloc(12 * sizeof(uint32_t))); - CHECK_ALLOCATION(macio_aa = (unsigned char *) malloc(5 * sizeof(uint32_t))); - CHECK_ALLOCATION(ata_interrupts = (unsigned char *) malloc(6 * sizeof(uint32_t))); - CHECK_ALLOCATION(ata_reg = (unsigned char *) malloc(8 * sizeof(uint32_t))); - - of_store_32bit_in_host(uninorth_reg + 0, 0xe2000000); - of_store_32bit_in_host(uninorth_reg + 4, 0); /* not used? */ - of_add_prop(ofd, n, "reg", uninorth_reg, 2*sizeof(uint32_t), 0); - - of_store_32bit_in_host(uninorth_bus_range + 0, 0); - of_store_32bit_in_host(uninorth_bus_range + 4, 0); - of_add_prop(ofd, n, "bus-range", uninorth_bus_range, - 2*sizeof(uint32_t), 0); - - /* MEM: */ - of_store_32bit_in_host(uninorth_ranges + 0, 0x02000000); - of_store_32bit_in_host(uninorth_ranges + 4, 0); - of_store_32bit_in_host(uninorth_ranges + 8, 0); - of_store_32bit_in_host(uninorth_ranges + 12, 0xd0000000); - of_store_32bit_in_host(uninorth_ranges + 16, 0); - of_store_32bit_in_host(uninorth_ranges + 20, 0x04000000); - /* IO: */ - of_store_32bit_in_host(uninorth_ranges + 24, 0x01000000); - of_store_32bit_in_host(uninorth_ranges + 28, 0); - of_store_32bit_in_host(uninorth_ranges + 32, 0); - of_store_32bit_in_host(uninorth_ranges + 36, 0xe2000000); - of_store_32bit_in_host(uninorth_ranges + 40, 0); - of_store_32bit_in_host(uninorth_ranges + 44, 0x01000000); - of_add_prop(ofd, n, "ranges", uninorth_ranges, - 12*sizeof(uint32_t), 0); - - ic = of_add_device(ofd, macio, "/"); - memset(macio_aa, 0, 20); - of_store_32bit_in_host(macio_aa + 0, 15 << 11); /* pci tag */ - of_store_32bit_in_host(macio_aa + 8, 0xf3000000); - of_add_prop(ofd, macio, "assigned-addresses", macio_aa, - 5*sizeof(uint32_t), 0); -/* of_add_prop(ofd, n, "assigned-addresses", macio_aa, - 5*sizeof(uint32_t), 0); */ - of_add_prop_int32(ofd, "/chosen", "interrupt-controller", ic->handle); - - of_add_device(ofd, "bandit", "/"); - of_add_device(ofd, "gc", "/bandit"); - of_add_prop(ofd, "/bandit/gc", "assigned-addresses", macio_aa, - 5*sizeof(uint32_t), 0); - - if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || - diskimage_exist(machine, 1, DISKIMAGE_IDE)) { - char tmpstr[400]; - of_add_device(ofd, "ata", "/bandit/gc"); - of_add_prop_str(machine, ofd, "/bandit/gc/ata", "name", "ata"); - of_add_prop_str(machine, ofd, "/bandit/gc/ata", "compatible", - "heathrow-ata"); - of_store_32bit_in_host(ata_interrupts + 0, 13); - of_store_32bit_in_host(ata_interrupts + 4, 0); - of_store_32bit_in_host(ata_interrupts + 8, 0); - of_store_32bit_in_host(ata_interrupts + 12, 0); - of_store_32bit_in_host(ata_interrupts + 16, 0); - of_store_32bit_in_host(ata_interrupts + 20, 0); - of_add_prop(ofd, "/bandit/gc/ata", "interrupts", ata_interrupts, - 6*sizeof(uint32_t), 0); - of_store_32bit_in_host(ata_reg + 0, 0x20000); - of_store_32bit_in_host(ata_reg + 4, 0); - of_store_32bit_in_host(ata_reg + 8, 0x21000); - of_store_32bit_in_host(ata_reg + 12, 0x22000); - of_store_32bit_in_host(ata_reg + 16, 0); - of_store_32bit_in_host(ata_reg + 20, 0); - of_store_32bit_in_host(ata_reg + 24, 0); - of_store_32bit_in_host(ata_reg + 28, 0); - of_add_prop(ofd, "/bandit/gc/ata", "reg", ata_reg, - 8*sizeof(uint32_t), 0); - - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0xf3020000 " - "irq=%s.cpu[%i].gc.lo.21 addr_mult=0x10", machine->path, - machine->bootstrap_cpu); - device_add(machine, tmpstr); - } -} - - -/* - * of_emul_init(): - * - * This function creates an OpenFirmware emulation instance. - */ -struct of_data *of_emul_init(struct machine *machine, struct vfb_data *vfb_data, - uint64_t fb_addr, int fb_xsize, int fb_ysize) -{ - unsigned char *memory_reg, *memory_av; - unsigned char *root_address_cells, *root_size_cells; - unsigned char *zs_assigned_addresses; - struct of_device *memory_dev, *mmu, *devstdout, *devstdin; - struct of_data *ofd; - int i; - - CHECK_ALLOCATION(ofd = (struct of_data *) malloc(sizeof(struct of_data))); - memset(ofd, 0, sizeof(struct of_data)); - - ofd->vfb_data = vfb_data; - - /* Devices: */ - - /* Root = device 1 */ - of_add_device(ofd, "", ""); - of_add_prop_str(machine, ofd, "/", "model", "GXemul OpenFirmware machine"); - - CHECK_ALLOCATION(root_address_cells = (unsigned char *) malloc(1 * sizeof(uint32_t))); - of_store_32bit_in_host(root_address_cells, 0); - of_add_prop(ofd, "/", "#address-cells", root_address_cells, 1 * sizeof(uint32_t), 0); - - CHECK_ALLOCATION(root_size_cells = (unsigned char *) malloc(1 * sizeof(uint32_t))); - of_store_32bit_in_host(root_size_cells, 0); - of_add_prop(ofd, "/", "#size-cells", root_size_cells, 1 * sizeof(uint32_t), 0); - - of_add_device(ofd, "io", "/"); - devstdin = of_add_device(ofd, "stdin", "/io"); - devstdout = of_add_device(ofd, "stdout", "/io"); - - if (machine->x11_md.in_use) { - fatal("!\n! TODO: keyboard + framebuffer for MacPPC\n!\n"); - - of_add_prop_str(machine, ofd, "/io/stdin", "name", - "keyboard"); - of_add_prop_str(machine, ofd, "/io", "name", "adb"); - - of_add_prop_str(machine, ofd, "/io/stdout", "device_type", - "display"); - of_add_prop_int32(ofd, "/io/stdout", "width", fb_xsize); - of_add_prop_int32(ofd, "/io/stdout", "height", fb_ysize); - of_add_prop_int32(ofd, "/io/stdout", "linebytes", fb_xsize * 1); - of_add_prop_int32(ofd, "/io/stdout", "depth", 8); - of_add_prop_int32(ofd, "/io/stdout", "address", fb_addr); - } else { - CHECK_ALLOCATION(zs_assigned_addresses = (unsigned char *) malloc(12)); - memset(zs_assigned_addresses, 0, 12); - - of_add_prop_str(machine, ofd, "/io/stdin", "name", "ch-b"); - of_add_prop_str(machine, ofd, "/io/stdin", "device_type", - "serial"); - of_add_prop_int32(ofd, "/io/stdin", "reg", 0xf3013000); - of_add_prop(ofd, "/io/stdin", "assigned-addresses", - zs_assigned_addresses, 12, 0); - - of_add_prop_str(machine, ofd, "/io/stdout", "device_type", - "serial"); - } - - of_add_device(ofd, "cpus", "/"); - for (i=0; incpus; i++) { - char tmp[50]; - snprintf(tmp, sizeof(tmp), "@%x", i); - of_add_device(ofd, tmp, "/cpus"); - snprintf(tmp, sizeof(tmp), "/cpus/@%x", i); - of_add_prop_str(machine, ofd, tmp, "device_type", "cpu"); - of_add_prop_int32(ofd, tmp, "timebase-frequency", - machine->emulated_hz / 4); - of_add_prop_int32(ofd, tmp, "clock-frequency", - machine->emulated_hz); - of_add_prop_int32(ofd, tmp, "reg", i); - } - - mmu = of_add_device(ofd, "mmu", "/"); - - /* TODO: */ - of_add_prop(ofd, "/mmu", "translations", NULL, 0, 0); - - of_add_device(ofd, "chosen", "/"); - of_add_prop_int32(ofd, "/chosen", "mmu", mmu->handle); - of_add_prop_int32(ofd, "/chosen", "stdin", devstdin->handle); - of_add_prop_int32(ofd, "/chosen", "stdout", devstdout->handle); - - memory_dev = of_add_device(ofd, "memory", "/"); - CHECK_ALLOCATION(memory_reg = (unsigned char *) malloc(2 * sizeof(uint32_t))); - CHECK_ALLOCATION(memory_av = (unsigned char *) malloc(2 * sizeof(uint32_t))); - - of_store_32bit_in_host(memory_reg + 0, 0); - of_store_32bit_in_host(memory_reg + 4, machine->physical_ram_in_mb<<20); - of_store_32bit_in_host(memory_av + 0, 10 << 20); - of_store_32bit_in_host(memory_av + 4, (machine->physical_ram_in_mb - 10) << 20); - of_add_prop(ofd, "/memory", "reg", memory_reg, 2 * sizeof(uint32_t), 0); - of_add_prop(ofd, "/memory", "available", memory_av, 2*sizeof(uint32_t),0); - of_add_prop_str(machine, ofd, "/memory", "name", "memory"); - of_add_prop_str(machine, ofd, "/memory","device_type","memory"/*?*/); - - of_add_prop_int32(ofd, "/chosen", "memory", memory_dev->handle); - - /* Services: */ - of_add_service(ofd, "call-method", of__call_method_2_2, 2, 2); - of_add_service(ofd, "call-method", of__call_method_3_4, 3, 4); - of_add_service(ofd, "call-method", of__call_method_5_2, 5, 2); - of_add_service(ofd, "call-method", of__call_method_6_1, 6, 1); - of_add_service(ofd, "call-method", of__call_method_6_2, 6, 2); - of_add_service(ofd, "child", of__child, 1, 1); - of_add_service(ofd, "claim", of__claim, 3, 1); - of_add_service(ofd, "exit", of__exit, 0, 0); - of_add_service(ofd, "finddevice", of__finddevice, 1, 1); - of_add_service(ofd, "getprop", of__getprop, 4, 1); - of_add_service(ofd, "getproplen", of__getproplen, 2, 1); - of_add_service(ofd, "instance-to-package", - of__instance_to_package, 1, 1); - of_add_service(ofd, "interpret", of__interpret_1, 1, 1); - of_add_service(ofd, "interpret", of__interpret_2, 1, 2); - of_add_service(ofd, "package-to-path", of__package_to_path, 3, 1); - of_add_service(ofd, "parent", of__parent, 1, 1); - of_add_service(ofd, "peer", of__peer, 1, 1); - of_add_service(ofd, "open", of__open, 1, 1); - of_add_service(ofd, "read", of__read, 3, 1); - of_add_service(ofd, "write", of__write, 3, 1); - - if (verbose >= 2) - of_dump_all(ofd); - - machine->md.of_data = ofd; - - return ofd; -} - - -/* - * of_emul(): - * - * OpenFirmware call emulation. - */ -int of_emul(struct cpu *cpu) -{ - int i, nargs, nret, ofs, retval = 0; - char service[50]; - char *arg[OF_N_MAX_ARGS]; - uint64_t base, ptr; - struct of_service *os; - struct of_data *of_data = cpu->machine->md.of_data; - - if (of_data == NULL) { - fatal("of_emul(): no of_data struct?\n"); - exit(1); - } - - /* - * The first argument register points to "prom_args": - * - * char *service; (probably 32 bit) - * int nargs; - * int nret; - * char *args[10]; - */ - - switch (cpu->machine->arch) { - case ARCH_ARM: - base = cpu->cd.arm.r[0]; - break; - case ARCH_PPC: - base = cpu->cd.ppc.gpr[3]; - break; - default:fatal("of_emul(): unimplemented arch (TODO)\n"); - exit(1); - } - - /* TODO: how about 64-bit OpenFirmware? */ - ptr = load_32bit_word(cpu, base); - nargs = load_32bit_word(cpu, base + 4); - nret = load_32bit_word(cpu, base + 8); - - readstr(cpu, ptr, service, sizeof(service)); - - debug("[ of: %s(", service); - ofs = 12; - for (i=0; i 0) - debug(", "); - if (i >= OF_N_MAX_ARGS) { - fatal("TOO MANY ARGS!"); - continue; - } - - ptr = load_32bit_word(cpu, base + ofs); - - CHECK_ALLOCATION(arg[i] = (char *) malloc(OF_ARG_MAX_LEN + 1)); - memset(arg[i], 0, OF_ARG_MAX_LEN + 1); - - x = ptr; - if (x > -256 && x < 256) { - debug("%i", x); - } else { - readstr(cpu, ptr, arg[i], OF_ARG_MAX_LEN); - if (arg[i][0]) - debug("\"%s\"", arg[i]); - else - debug("0x%x", x); - } - ofs += sizeof(uint32_t); - } - debug(") ]\n"); - - /* Note: base + ofs points to the first return slot. */ - - os = of_data->of_services; - while (os != NULL) { - if (strcmp(service, os->name) == 0 && - nargs == os->n_args && nret == os->n_ret_args) { - retval = os->f(cpu, arg, base, ofs); - break; - } - os = os->next; - } - - if (os == NULL) { - quiet_mode = 0; - cpu_register_dump(cpu->machine, cpu, 1, 0); - printf("\n"); - fatal("[ of: unimplemented service \"%s\" with %i input " - "args and %i output values ]\n", service, nargs, nret); - cpu->running = 0; - exit(1); - } - - for (i=0; imachine->arch) { - case ARCH_ARM: - cpu->cd.arm.r[0] = retval; - break; - case ARCH_PPC: - cpu->cd.ppc.gpr[3] = retval; - break; - default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n"); - exit(1); - } - - return 1; -} - diff -Nru gxemul-0.6.2/src/promemul/ps2_bios.c gxemul-0.7.0+dfsg/src/promemul/ps2_bios.c --- gxemul-0.6.2/src/promemul/ps2_bios.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/ps2_bios.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2003-2009 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: Playstation 2 SIFBIOS emulation + */ + +#include +#include +#include +#include +#include +#include + +#include "console.h" +#include "cpu.h" +#include "cpu_mips.h" +#include "machine.h" +#include "memory.h" + + +extern int quiet_mode; + + +/* + * playstation2_sifbios_emul(): + */ +int playstation2_sifbios_emul(struct cpu *cpu) +{ + int callnr; + + callnr = cpu->cd.mips.gpr[MIPS_GPR_A0]; + + switch (callnr) { + case 0: /* getver() */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0x200; /* TODO */ + break; + case 1: /* halt(int mode) */ + debug("[ SIFBIOS halt(0x%" PRIx64") ]\n", + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); + cpu->running = 0; + break; + case 2: /* setdve(int mode) */ + debug("[ SIFBIOS setdve(0x%" PRIx64") ]\n", + (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); + break; + case 3: /* putchar(int ch) */ + /* debug("[ SIFBIOS putchar(0x%x) ]\n", + (char)cpu->cd.mips.gpr[MIPS_GPR_A1]); */ + console_putchar(cpu->machine->main_console_handle, + cpu->cd.mips.gpr[MIPS_GPR_A1]); + break; + case 4: /* getchar() */ + /* This is untested. TODO */ + /* debug("[ SIFBIOS getchar() ]\n"; */ + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + if (console_charavail(cpu->machine->main_console_handle)) + cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar( + cpu->machine->main_console_handle); + break; + case 16: /* dma_init() */ + debug("[ SIFBIOS dma_init() ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ + break; + case 17: /* dma_exit() */ + debug("[ SIFBIOS dma_exit() ]\n"); + break; + case 32: /* cmd_init() */ + debug("[ SIFBIOS cmd_init() ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ + break; + case 33: /* cmd_exit() */ + debug("[ SIFBIOS cmd_exit() ]\n"); + break; + case 48: + debug("[ SIFBIOS rpc_init(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ + break; + case 49: + debug("[ SIFBIOS rpc_exit(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ + break; + case 51: + debug("[ SIFBIOS rpc_bind(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; /* TODO */ + break; + case 64: + fatal("[ SIFBIOS SBR_IOPH_INIT(0x%" PRIx32",0x%" PRIx32",0x%" + PRIx32"): TODO ]\n", + (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A1], + (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A2], + (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A3]); + + /* + * This is really really ugly: TODO + * + * Linux and NetBSD seem to work, but it's an ugly hack. + * This should really be a callback thingy... + * + * NetBSD has a done-word which should be set to 1. + * Linux has one done-word which should be set to 1, and + * one which should be set to 0. + * + * The code as it is right now probably overwrites stuff in + * memory that shouldn't be touched. Not good. + * + * Linux: err = sbios_rpc(SBR_IOPH_INIT, NULL, &result); + * err should be 0 (just as NetBSD), + * and result should be set to 0 as well. + */ + { + uint32_t tmpaddr; + + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 0); + fatal(" +0: %08x\n", tmpaddr); + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 4); + fatal(" +4: %08x\n", tmpaddr); + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 8); + fatal(" +8: %08x\n", tmpaddr); + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); + fatal(" +12: %08x\n", tmpaddr); + + /* TODO: This is probably netbsd specific */ + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); + fatal("tmpaddr 1 = 0x%08x\n", tmpaddr); + + /* "done" word for NetBSD: */ + store_32bit_word(cpu, tmpaddr, 1); + /* "done" word A for Linux: */ + store_32bit_word(cpu, tmpaddr + 4, 1); + /* "done" word B for Linux: */ + store_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 0, 0); + } + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 65: + fatal("[ SIFBIOS alloc iop heap(0x" PRIx32") ]\n", + (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A1]); + + /* + * Linux uses this to allocate "heap" for the OHCI USB + * controller. + * + * TODO: This nave implementation does not allow for a + * "free iop heap" function: :-/ + */ + + { + uint32_t tmpaddr; + static uint32_t return_addr = 0x1000; + /* 0xbc000000; */ + uint32_t size; + + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 0); + fatal(" +0: %08x (result should be placed here)\n", + tmpaddr); + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 4); + fatal(" +4: %08x (*arg)\n", tmpaddr); + size = load_32bit_word(cpu, tmpaddr + 0); + fatal(" size = %08x\n", size); + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 8); + fatal(" +8: %08x (*func (void *, int))\n", tmpaddr); + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); + fatal(" +12: %08x (*para)\n", tmpaddr); + + /* TODO: This is probably netbsd specific */ + tmpaddr = load_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); + fatal("tmpaddr 1 = 0x%08x\n", tmpaddr); + + /* "done" word for NetBSD: */ + store_32bit_word(cpu, tmpaddr, 1); + /* "done" word A for Linux: */ + store_32bit_word(cpu, tmpaddr + 4, 1); + + /* Result: */ + store_32bit_word(cpu, + cpu->cd.mips.gpr[MIPS_GPR_A1] + 0, return_addr); + + return_addr += size; + /* Round up to next page: */ + return_addr += 4095; + return_addr &= ~4095; + } + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + break; + case 66: + debug("[ SIFBIOS iopmem_free(): TODO ]\n"); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ + break; + default: + quiet_mode = 0; + cpu_register_dump(cpu->machine, cpu, 1, 0x1); + printf("\n"); + fatal("Playstation 2 SIFBIOS emulation: " + "unimplemented call nr 0x%x\n", callnr); + cpu->running = 0; + } + + return 1; +} + diff -Nru gxemul-0.6.2/src/promemul/ps2_bios.cc gxemul-0.7.0+dfsg/src/promemul/ps2_bios.cc --- gxemul-0.6.2/src/promemul/ps2_bios.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/ps2_bios.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2003-2009 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: Playstation 2 SIFBIOS emulation - */ - -#include -#include -#include -#include -#include -#include - -#include "console.h" -#include "cpu.h" -#include "cpu_mips.h" -#include "machine.h" -#include "memory.h" - - -extern int quiet_mode; - - -/* - * playstation2_sifbios_emul(): - */ -int playstation2_sifbios_emul(struct cpu *cpu) -{ - int callnr; - - callnr = cpu->cd.mips.gpr[MIPS_GPR_A0]; - - switch (callnr) { - case 0: /* getver() */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0x200; /* TODO */ - break; - case 1: /* halt(int mode) */ - debug("[ SIFBIOS halt(0x%" PRIx64") ]\n", - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); - cpu->running = 0; - break; - case 2: /* setdve(int mode) */ - debug("[ SIFBIOS setdve(0x%" PRIx64") ]\n", - (uint64_t) cpu->cd.mips.gpr[MIPS_GPR_A1]); - break; - case 3: /* putchar(int ch) */ - /* debug("[ SIFBIOS putchar(0x%x) ]\n", - (char)cpu->cd.mips.gpr[MIPS_GPR_A1]); */ - console_putchar(cpu->machine->main_console_handle, - cpu->cd.mips.gpr[MIPS_GPR_A1]); - break; - case 4: /* getchar() */ - /* This is untested. TODO */ - /* debug("[ SIFBIOS getchar() ]\n"; */ - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - if (console_charavail(cpu->machine->main_console_handle)) - cpu->cd.mips.gpr[MIPS_GPR_V0] = console_readchar( - cpu->machine->main_console_handle); - break; - case 16: /* dma_init() */ - debug("[ SIFBIOS dma_init() ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ - break; - case 17: /* dma_exit() */ - debug("[ SIFBIOS dma_exit() ]\n"); - break; - case 32: /* cmd_init() */ - debug("[ SIFBIOS cmd_init() ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ - break; - case 33: /* cmd_exit() */ - debug("[ SIFBIOS cmd_exit() ]\n"); - break; - case 48: - debug("[ SIFBIOS rpc_init(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ - break; - case 49: - debug("[ SIFBIOS rpc_exit(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ - break; - case 51: - debug("[ SIFBIOS rpc_bind(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; /* TODO */ - break; - case 64: - fatal("[ SIFBIOS SBR_IOPH_INIT(0x%" PRIx32",0x%" PRIx32",0x%" - PRIx32"): TODO ]\n", - (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A1], - (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A2], - (uint32_t) cpu->cd.mips.gpr[MIPS_GPR_A3]); - - /* - * This is really really ugly: TODO - * - * Linux and NetBSD seem to work, but it's an ugly hack. - * This should really be a callback thingy... - * - * NetBSD has a done-word which should be set to 1. - * Linux has one done-word which should be set to 1, and - * one which should be set to 0. - * - * The code as it is right now probably overwrites stuff in - * memory that shouldn't be touched. Not good. - * - * Linux: err = sbios_rpc(SBR_IOPH_INIT, NULL, &result); - * err should be 0 (just as NetBSD), - * and result should be set to 0 as well. - */ - { - uint32_t tmpaddr; - - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 0); - fatal(" +0: %08x\n", tmpaddr); - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 4); - fatal(" +4: %08x\n", tmpaddr); - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 8); - fatal(" +8: %08x\n", tmpaddr); - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); - fatal(" +12: %08x\n", tmpaddr); - - /* TODO: This is probably netbsd specific */ - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); - fatal("tmpaddr 1 = 0x%08x\n", tmpaddr); - - /* "done" word for NetBSD: */ - store_32bit_word(cpu, tmpaddr, 1); - /* "done" word A for Linux: */ - store_32bit_word(cpu, tmpaddr + 4, 1); - /* "done" word B for Linux: */ - store_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 0, 0); - } - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 65: - fatal("[ SIFBIOS alloc iop heap(0x" PRIx32") ]\n", - (uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A1]); - - /* - * Linux uses this to allocate "heap" for the OHCI USB - * controller. - * - * TODO: This nave implementation does not allow for a - * "free iop heap" function: :-/ - */ - - { - uint32_t tmpaddr; - static uint32_t return_addr = 0x1000; - /* 0xbc000000; */ - uint32_t size; - - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 0); - fatal(" +0: %08x (result should be placed here)\n", - tmpaddr); - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 4); - fatal(" +4: %08x (*arg)\n", tmpaddr); - size = load_32bit_word(cpu, tmpaddr + 0); - fatal(" size = %08x\n", size); - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 8); - fatal(" +8: %08x (*func (void *, int))\n", tmpaddr); - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); - fatal(" +12: %08x (*para)\n", tmpaddr); - - /* TODO: This is probably netbsd specific */ - tmpaddr = load_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 12); - fatal("tmpaddr 1 = 0x%08x\n", tmpaddr); - - /* "done" word for NetBSD: */ - store_32bit_word(cpu, tmpaddr, 1); - /* "done" word A for Linux: */ - store_32bit_word(cpu, tmpaddr + 4, 1); - - /* Result: */ - store_32bit_word(cpu, - cpu->cd.mips.gpr[MIPS_GPR_A1] + 0, return_addr); - - return_addr += size; - /* Round up to next page: */ - return_addr += 4095; - return_addr &= ~4095; - } - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - break; - case 66: - debug("[ SIFBIOS iopmem_free(): TODO ]\n"); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* TODO */ - break; - default: - quiet_mode = 0; - cpu_register_dump(cpu->machine, cpu, 1, 0x1); - printf("\n"); - fatal("Playstation 2 SIFBIOS emulation: " - "unimplemented call nr 0x%x\n", callnr); - cpu->running = 0; - } - - return 1; -} - diff -Nru gxemul-0.6.2/src/promemul/sh_ipl_g.c gxemul-0.7.0+dfsg/src/promemul/sh_ipl_g.c --- gxemul-0.6.2/src/promemul/sh_ipl_g.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/sh_ipl_g.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2007-2009 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: SH-IPL+G emulation + * + * Very basic, only what is needed to get OpenBSD/landisk booting. + * (SH-IPL+G stands for SuperH Initial Program Loader + GDB stub.) + */ + +#include +#include +#include +#include + +#include "cpu.h" +#include "cpu_sh.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" + +#include "thirdparty/sh4_exception.h" + + +/* + * sh_ipl_g_emul_init(): + */ +void sh_ipl_g_emul_init(struct machine *machine) +{ + struct cpu *cpu = machine->cpus[0]; + + cpu->cd.sh.vbr = 0x8c000000; + store_16bit_word(cpu, 0x8c000100, SH_INVALID_INSTR); + store_16bit_word(cpu, 0x8c000102, 0x002b); /* rte */ + store_16bit_word(cpu, 0x8c000104, 0x0009); /* nop */ +} + + +/* + * sh_ipl_g_promcall(): + * + * SH-IPL+G PROM call emulation. + */ +static int sh_ipl_g_promcall(struct cpu *cpu) +{ + /* + * SH-IPL+G call numbers are in R0: + * + * NOTE: r_bank[0], since this is in a trap handler! + */ + switch (cpu->cd.sh.r_bank[0]) { + + case 4: /* Get memory size. */ + cpu->cd.sh.r_bank[0] = 64 * 1048576; + /* Note: cpu->machine->physical_ram_in_mb * 1048576 + would be more correct, but physical_ram_in_mb is + set to 2 for landisk emulation... */ + break; + + default:cpu_register_dump(cpu->machine, cpu, 1, 0); + printf("\n"); + fatal("[ SH-IPL+G PROM emulation: unimplemented function 0x%" + PRIx32" ]\n", cpu->cd.sh.r_bank[0]); + cpu->running = 0; + return 0; + } + + return 1; +} + + +/* + * sh_ipl_g_emul(): + */ +int sh_ipl_g_emul(struct cpu *cpu) +{ + /* SH-IPL+G calls are "trapa #63": */ + if (cpu->cd.sh.expevt == EXPEVT_TRAPA && + cpu->cd.sh.tra == 0xfc) { + return sh_ipl_g_promcall(cpu); + } else { + cpu_register_dump(cpu->machine, cpu, 1, 0); + printf("\n"); + fatal("[ SH-IPL+G PROM emulation: expevt=0x%x, " + " tra=0x%x ]\n", (int)cpu->cd.sh.expevt, + (int)cpu->cd.sh.tra); + cpu->running = 0; + return 0; + } +} + diff -Nru gxemul-0.6.2/src/promemul/sh_ipl_g.cc gxemul-0.7.0+dfsg/src/promemul/sh_ipl_g.cc --- gxemul-0.6.2/src/promemul/sh_ipl_g.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/sh_ipl_g.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2007-2009 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: SH-IPL+G emulation - * - * Very basic, only what is needed to get OpenBSD/landisk booting. - * (SH-IPL+G stands for SuperH Initial Program Loader + GDB stub.) - */ - -#include -#include -#include -#include - -#include "cpu.h" -#include "cpu_sh.h" -#include "machine.h" -#include "memory.h" -#include "misc.h" - -#include "thirdparty/sh4_exception.h" - - -/* - * sh_ipl_g_emul_init(): - */ -void sh_ipl_g_emul_init(struct machine *machine) -{ - struct cpu *cpu = machine->cpus[0]; - - cpu->cd.sh.vbr = 0x8c000000; - store_16bit_word(cpu, 0x8c000100, SH_INVALID_INSTR); - store_16bit_word(cpu, 0x8c000102, 0x002b); /* rte */ - store_16bit_word(cpu, 0x8c000104, 0x0009); /* nop */ -} - - -/* - * sh_ipl_g_promcall(): - * - * SH-IPL+G PROM call emulation. - */ -static int sh_ipl_g_promcall(struct cpu *cpu) -{ - /* - * SH-IPL+G call numbers are in R0: - * - * NOTE: r_bank[0], since this is in a trap handler! - */ - switch (cpu->cd.sh.r_bank[0]) { - - case 4: /* Get memory size. */ - cpu->cd.sh.r_bank[0] = 64 * 1048576; - /* Note: cpu->machine->physical_ram_in_mb * 1048576 - would be more correct, but physical_ram_in_mb is - set to 2 for landisk emulation... */ - break; - - default:cpu_register_dump(cpu->machine, cpu, 1, 0); - printf("\n"); - fatal("[ SH-IPL+G PROM emulation: unimplemented function 0x%" - PRIx32" ]\n", cpu->cd.sh.r_bank[0]); - cpu->running = 0; - return 0; - } - - return 1; -} - - -/* - * sh_ipl_g_emul(): - */ -int sh_ipl_g_emul(struct cpu *cpu) -{ - /* SH-IPL+G calls are "trapa #63": */ - if (cpu->cd.sh.expevt == EXPEVT_TRAPA && - cpu->cd.sh.tra == 0xfc) { - return sh_ipl_g_promcall(cpu); - } else { - cpu_register_dump(cpu->machine, cpu, 1, 0); - printf("\n"); - fatal("[ SH-IPL+G PROM emulation: expevt=0x%x, " - " tra=0x%x ]\n", (int)cpu->cd.sh.expevt, - (int)cpu->cd.sh.tra); - cpu->running = 0; - return 0; - } -} - diff -Nru gxemul-0.6.2/src/promemul/yamon.c gxemul-0.7.0+dfsg/src/promemul/yamon.c --- gxemul-0.6.2/src/promemul/yamon.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/yamon.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2005-2009 Anders Gavare. 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. The name of the author 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. + * + * + * COMMENT: YAMON emulation + * + * (Very basic, only what is needed to get NetBSD booting.) + */ + +#include +#include +#include +#include + +#include "console.h" +#include "cpu.h" +#include "cpu_mips.h" +#include "machine.h" +#include "memory.h" +#include "misc.h" +#include "net.h" + +#include "thirdparty/yamon.h" + + +/* + * yamon_machine_setup(): + */ +void yamon_machine_setup(struct machine *machine, uint64_t env) +{ + char tmps[200]; + char macaddr[6]; + uint64_t tmpptr = env + 0x400; + struct cpu *cpu = machine->cpus[0]; + + /* + * Standard YAMON environment variables: + * + * baseboardserial + * bootfile TODO + * bootprot TODO: Non-tftp boot + * bootserport + * bootserver + * cpuconfig TODO + * ethaddr + * fpu TODO + * gateway + * ipaddr TODO: Don't hardcode! + * memsize + * modetty0 + * modetty1 + * prompt + * start TODO + * startdelay TODO + * subnetmask TODO: Real subnet mask + * yamonrev + */ + + add_environment_string_dual(cpu, &env, &tmpptr, + "baseboardserial", "0000000000"); + + /* TODO: Disk boot! */ + add_environment_string_dual(cpu, &env, &tmpptr, "bootprot", "tftp"); + + add_environment_string_dual(cpu, &env, &tmpptr, "bootserport", "tty0"); + + add_environment_string_dual(cpu, &env, &tmpptr, + "bootserver", "10.0.0.254"); + + net_generate_unique_mac(machine, (unsigned char *) macaddr); + snprintf(tmps, sizeof(tmps), "%02x.%02x.%02x.%02x.%02x.%02x", + macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); + add_environment_string_dual(cpu, &env, &tmpptr, "ethaddr", tmps); + + add_environment_string_dual(cpu, &env, &tmpptr, + "gateway", "10.0.0.254"); + + /* TODO: Don't hardcode! */ + add_environment_string_dual(cpu, &env, &tmpptr, + "ipaddr", "10.0.0.1"); + + snprintf(tmps, sizeof(tmps), "0x%08x", machine->physical_ram_in_mb<<20); + add_environment_string_dual(cpu, &env, &tmpptr, "memsize", tmps); + + add_environment_string_dual(cpu, &env, &tmpptr, + "modetty0", "38400,n,8,1,none"); + + add_environment_string_dual(cpu, &env, &tmpptr, + "modetty1", "38400,n,8,1,none"); + + add_environment_string_dual(cpu, &env, &tmpptr, "prompt", "YAMON"); + + add_environment_string_dual(cpu, &env, &tmpptr, "yamonrev", "02.06"); + + /* TODO: Real subnet mask: */ + add_environment_string_dual(cpu, &env, &tmpptr, + "subnetmask", "255.0.0.0"); + + + /* FreeBSD development specific: */ + snprintf(tmps, sizeof(tmps), "%i", machine->emulated_hz / 1000); + add_environment_string_dual(cpu, &env, &tmpptr, "khz", tmps); + + /* NULL terminate: */ + tmpptr = 0; + add_environment_string_dual(cpu, &env, &tmpptr, NULL, NULL); +} + + +/* + * yamon_emul(): + * + * YAMON emulation (for evbmips). + */ +int yamon_emul(struct cpu *cpu) +{ + uint32_t ofs = (cpu->pc & 0xff) + YAMON_FUNCTION_BASE; + uint8_t ch; + int n; + uint32_t oid; + uint64_t paddr, psize; + + switch (ofs) { + + case YAMON_PRINT_COUNT_OFS: + /* + * print count: + * a1 = string + * a2 = count + */ + n = 0; + while (n < (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]) { + cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr + [MIPS_GPR_A1] + n, &ch, sizeof(ch), MEM_READ, + CACHE_DATA | NO_EXCEPTIONS); + console_putchar(cpu->machine->main_console_handle, ch); + n++; + } + break; + + case YAMON_EXIT_OFS: + /* + * exit + */ + debug("[ yamon_emul(): exit ]\n"); + cpu->running = 0; + break; + + /* YAMON_FLUSH_CACHE_OFS: TODO */ + /* YAMON_PRINT_OFS: TODO */ + /* YAMON_REG_CPU_ISR_OFS: TODO */ + /* YAMON_DEREG_CPU_ISR_OFS: TODO */ + /* YAMON_REG_IC_ISR_OFS: TODO */ + /* YAMON_DEREG_IC_ISR_OFS: TODO */ + /* YAMON_REG_ESR_OFS: TODO */ + /* YAMON_DEREG_ESR_OFS: TODO */ + + case YAMON_GETCHAR_OFS: + n = console_readchar(cpu->machine->main_console_handle); + /* Note: -1 (if no char was available) becomes 0xff: */ + ch = n; + cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[ + MIPS_GPR_A1], &ch, sizeof(ch), MEM_WRITE, + CACHE_DATA | NO_EXCEPTIONS); + break; + + case YAMON_SYSCON_READ_OFS: + /* + * syscon_read(oid [a0], addr [a1], size [a2]) + */ + + oid = cpu->cd.mips.gpr[MIPS_GPR_A0]; + paddr = cpu->cd.mips.gpr[MIPS_GPR_A1]; + psize = cpu->cd.mips.gpr[MIPS_GPR_A2]; + + switch (oid) { + case SYSCON_BOARD_CPU_CLOCK_FREQ_ID: + if (psize == sizeof(uint32_t)) { + uint32_t freq = cpu->machine->emulated_hz; + + debug("[ yamon_emul(): reporting CPU " + "frequency of %u ]\n", (unsigned int) + freq); + + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) + freq = LE32_TO_HOST(freq); + else + freq = BE32_TO_HOST(freq); + + cpu->memory_rw(cpu, cpu->mem, (int32_t)paddr, + (unsigned char *) (void *) &freq, sizeof(freq), MEM_WRITE, + CACHE_DATA | NO_EXCEPTIONS); + + cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; + } else { + cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; + } + break; + + default: + fatal("[ yamon_emul(): unimplemented object id 0x%" + PRIx32" ]\n", oid); + cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; + } + break; + + default: + cpu_register_dump(cpu->machine, cpu, 1, 0); + printf("\n"); + fatal("[ yamon_emul(): unimplemented yamon function 0x%" + PRIx32" ]\n", ofs); + cpu->running = 0; + } + + return 1; +} + diff -Nru gxemul-0.6.2/src/promemul/yamon.cc gxemul-0.7.0+dfsg/src/promemul/yamon.cc --- gxemul-0.6.2/src/promemul/yamon.cc 2019-06-22 18:23:26.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/promemul/yamon.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2005-2009 Anders Gavare. 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. The name of the author 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. - * - * - * COMMENT: YAMON emulation - * - * (Very basic, only what is needed to get NetBSD booting.) - */ - -#include -#include -#include -#include - -#include "console.h" -#include "cpu.h" -#include "cpu_mips.h" -#include "machine.h" -#include "memory.h" -#include "misc.h" -#include "net.h" - -#include "thirdparty/yamon.h" - - -/* - * yamon_machine_setup(): - */ -void yamon_machine_setup(struct machine *machine, uint64_t env) -{ - char tmps[200]; - char macaddr[6]; - uint64_t tmpptr = env + 0x400; - struct cpu *cpu = machine->cpus[0]; - - /* - * Standard YAMON environment variables: - * - * baseboardserial - * bootfile TODO - * bootprot TODO: Non-tftp boot - * bootserport - * bootserver - * cpuconfig TODO - * ethaddr - * fpu TODO - * gateway - * ipaddr TODO: Don't hardcode! - * memsize - * modetty0 - * modetty1 - * prompt - * start TODO - * startdelay TODO - * subnetmask TODO: Real subnet mask - * yamonrev - */ - - add_environment_string_dual(cpu, &env, &tmpptr, - "baseboardserial", "0000000000"); - - /* TODO: Disk boot! */ - add_environment_string_dual(cpu, &env, &tmpptr, "bootprot", "tftp"); - - add_environment_string_dual(cpu, &env, &tmpptr, "bootserport", "tty0"); - - add_environment_string_dual(cpu, &env, &tmpptr, - "bootserver", "10.0.0.254"); - - net_generate_unique_mac(machine, (unsigned char *) macaddr); - snprintf(tmps, sizeof(tmps), "%02x.%02x.%02x.%02x.%02x.%02x", - macaddr[0], macaddr[1], macaddr[2], - macaddr[3], macaddr[4], macaddr[5]); - add_environment_string_dual(cpu, &env, &tmpptr, "ethaddr", tmps); - - add_environment_string_dual(cpu, &env, &tmpptr, - "gateway", "10.0.0.254"); - - /* TODO: Don't hardcode! */ - add_environment_string_dual(cpu, &env, &tmpptr, - "ipaddr", "10.0.0.1"); - - snprintf(tmps, sizeof(tmps), "0x%08x", machine->physical_ram_in_mb<<20); - add_environment_string_dual(cpu, &env, &tmpptr, "memsize", tmps); - - add_environment_string_dual(cpu, &env, &tmpptr, - "modetty0", "38400,n,8,1,none"); - - add_environment_string_dual(cpu, &env, &tmpptr, - "modetty1", "38400,n,8,1,none"); - - add_environment_string_dual(cpu, &env, &tmpptr, "prompt", "YAMON"); - - add_environment_string_dual(cpu, &env, &tmpptr, "yamonrev", "02.06"); - - /* TODO: Real subnet mask: */ - add_environment_string_dual(cpu, &env, &tmpptr, - "subnetmask", "255.0.0.0"); - - - /* FreeBSD development specific: */ - snprintf(tmps, sizeof(tmps), "%i", machine->emulated_hz / 1000); - add_environment_string_dual(cpu, &env, &tmpptr, "khz", tmps); - - /* NULL terminate: */ - tmpptr = 0; - add_environment_string_dual(cpu, &env, &tmpptr, NULL, NULL); -} - - -/* - * yamon_emul(): - * - * YAMON emulation (for evbmips). - */ -int yamon_emul(struct cpu *cpu) -{ - uint32_t ofs = (cpu->pc & 0xff) + YAMON_FUNCTION_BASE; - uint8_t ch; - int n; - uint32_t oid; - uint64_t paddr, psize; - - switch (ofs) { - - case YAMON_PRINT_COUNT_OFS: - /* - * print count: - * a1 = string - * a2 = count - */ - n = 0; - while (n < (int32_t)cpu->cd.mips.gpr[MIPS_GPR_A2]) { - cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr - [MIPS_GPR_A1] + n, &ch, sizeof(ch), MEM_READ, - CACHE_DATA | NO_EXCEPTIONS); - console_putchar(cpu->machine->main_console_handle, ch); - n++; - } - break; - - case YAMON_EXIT_OFS: - /* - * exit - */ - debug("[ yamon_emul(): exit ]\n"); - cpu->running = 0; - break; - - /* YAMON_FLUSH_CACHE_OFS: TODO */ - /* YAMON_PRINT_OFS: TODO */ - /* YAMON_REG_CPU_ISR_OFS: TODO */ - /* YAMON_DEREG_CPU_ISR_OFS: TODO */ - /* YAMON_REG_IC_ISR_OFS: TODO */ - /* YAMON_DEREG_IC_ISR_OFS: TODO */ - /* YAMON_REG_ESR_OFS: TODO */ - /* YAMON_DEREG_ESR_OFS: TODO */ - - case YAMON_GETCHAR_OFS: - n = console_readchar(cpu->machine->main_console_handle); - /* Note: -1 (if no char was available) becomes 0xff: */ - ch = n; - cpu->memory_rw(cpu, cpu->mem, (int32_t)cpu->cd.mips.gpr[ - MIPS_GPR_A1], &ch, sizeof(ch), MEM_WRITE, - CACHE_DATA | NO_EXCEPTIONS); - break; - - case YAMON_SYSCON_READ_OFS: - /* - * syscon_read(oid [a0], addr [a1], size [a2]) - */ - - oid = cpu->cd.mips.gpr[MIPS_GPR_A0]; - paddr = cpu->cd.mips.gpr[MIPS_GPR_A1]; - psize = cpu->cd.mips.gpr[MIPS_GPR_A2]; - - switch (oid) { - case SYSCON_BOARD_CPU_CLOCK_FREQ_ID: - if (psize == sizeof(uint32_t)) { - uint32_t freq = cpu->machine->emulated_hz; - - debug("[ yamon_emul(): reporting CPU " - "frequency of %u ]\n", (unsigned int) - freq); - - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) - freq = LE32_TO_HOST(freq); - else - freq = BE32_TO_HOST(freq); - - cpu->memory_rw(cpu, cpu->mem, (int32_t)paddr, - (unsigned char *) (void *) &freq, sizeof(freq), MEM_WRITE, - CACHE_DATA | NO_EXCEPTIONS); - - cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; - } else { - cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; - } - break; - - default: - fatal("[ yamon_emul(): unimplemented object id 0x%" - PRIx32" ]\n", oid); - cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; - } - break; - - default: - cpu_register_dump(cpu->machine, cpu, 1, 0); - printf("\n"); - fatal("[ yamon_emul(): unimplemented yamon function 0x%" - PRIx32" ]\n", ofs); - cpu->running = 0; - } - - return 1; -} - diff -Nru gxemul-0.6.2/src/README gxemul-0.7.0+dfsg/src/README --- gxemul-0.6.2/src/README 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -GXemul's source code contains code from two trees; -the largest portion is the original emulator code written in plain C, -and the smaller (newer) portion is written in C++. All files have been -converted to a .cc (C++) extension, however, and C++ features may be -used by both the older and newer parts of the code. - - -NEW CODE --------- - - components - main - plugins - ui - - -SHARED ------- - - include - - -ORIGINAL EMULATOR CODE ----------------------- - - console - cpus (new cpus are in components/cpu/) - debugger (corresponds to main/CommandInterpreter.cc) - devices (corresponds to components/) - disk - file (new file loaders are in main/fileloaders/) - machines (new machines are in components/machines/) - net - old_main - promemul - symbol - diff -Nru gxemul-0.6.2/src/symbol/Makefile.skel gxemul-0.7.0+dfsg/src/symbol/Makefile.skel --- gxemul-0.6.2/src/symbol/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/symbol/Makefile.skel 2021-11-27 09:42:23.000000000 +0000 @@ -4,7 +4,7 @@ # Symbol handling support. # -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) +CFLAGS=$(CWARNINGS) $(COPTIM) $(DINCLUDE) OBJS=symbol.o symbol_demangle.o diff -Nru gxemul-0.6.2/src/symbol/symbol.c gxemul-0.7.0+dfsg/src/symbol/symbol.c --- gxemul-0.6.2/src/symbol/symbol.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/symbol/symbol.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2003-2009 Anders Gavare. 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. The name of the author 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. + * + * + * Address to symbol translation routines. + * + * This module is (probably) independent from the rest of the emulator. + * symbol_init() must be called before any other function in this file is used. + */ + +#include +#include +#include + +#include "symbol.h" + + +#define SYMBOLBUF_MAX 100 + + +/* + * symbol_nsymbols(): + * + * Return n_symbols. + */ +int symbol_nsymbols(struct symbol_context *sc) +{ + return sc->n_symbols; +} + + +/* + * get_symbol_addr(): + * + * Find a symbol by name. If addr is non-NULL, *addr is set to the symbol's + * address. Return value is 1 if the symbol is found, 0 otherwise. + * + * NOTE: This is O(n). + */ +int get_symbol_addr(struct symbol_context *sc, const char *symbol, uint64_t *addr) +{ + struct symbol *s; + + if (sc->sorted_array) { + int i; + for (i=0; in_symbols; i++) + if (strcmp(symbol, sc->first_symbol[i].name) == 0) { + if (addr != NULL) + *addr = sc->first_symbol[i].addr; + return 1; + } + } else { + s = sc->first_symbol; + while (s != NULL) { + if (strcmp(symbol, s->name) == 0) { + if (addr != NULL) + *addr = s->addr; + return 1; + } + s = s->next; + } + } + + return 0; +} + + +/* + * get_symbol_name_and_n_args(): + * + * Translate an address into a symbol name. The return value is a pointer + * to a static char array, containing the symbol name. (In other words, + * this function is not reentrant. This removes the need for memory allocation + * at the caller's side.) + * + * If offset is not a NULL pointer, *offset is set to the offset within + * the symbol. For example, if there is a symbol at address 0x1000 with + * length 0x100, and a caller wants to know the symbol name of address + * 0x1008, the symbol's name will be found in the static char array, and + * *offset will be set to 0x8. + * + * If n_argsp is non-NULL, *n_argsp is set to the symbol's n_args value. + * + * If no symbol was found, NULL is returned instead. + */ +static char symbol_buf[SYMBOLBUF_MAX+1]; +char *get_symbol_name_and_n_args(struct symbol_context *sc, uint64_t addr, + uint64_t *offset, int *n_argsp) +{ + struct symbol *s; + + if (sc->n_symbols == 0) + return NULL; + + if ((addr >> 32) == 0 && (addr & 0x80000000ULL)) + addr |= 0xffffffff00000000ULL; + + symbol_buf[0] = symbol_buf[SYMBOLBUF_MAX] = '\0'; + if (offset != NULL) + *offset = 0; + + if (!sc->sorted_array) { + /* Slow, linear O(n) search: */ + s = sc->first_symbol; + while (s != NULL) { + /* Found a match? */ + if (addr >= s->addr && addr < s->addr + s->len) { + if (addr == s->addr) + snprintf(symbol_buf, SYMBOLBUF_MAX, + "%s", s->name); + else + snprintf(symbol_buf, SYMBOLBUF_MAX, + "%s+0x%" PRIx64, s->name, (uint64_t) + (addr - s->addr)); + if (offset != NULL) + *offset = addr - s->addr; + if (n_argsp != NULL) + *n_argsp = s->n_args; + return symbol_buf; + } + s = s->next; + } + } else { + /* Faster, O(log n) search: */ + int lowest = 0, highest = sc->n_symbols - 1; + while (lowest <= highest) { + int ofs = (lowest + highest) / 2; + s = sc->first_symbol + ofs; + + /* Found a match? */ + if (addr >= s->addr && addr <= s->addr + (s->len - 1)) { + if (addr == s->addr) + snprintf(symbol_buf, SYMBOLBUF_MAX, + "%s%s%s", + color_symbol_ptr(), + s->name, + color_normal_ptr()); + else + snprintf(symbol_buf, SYMBOLBUF_MAX, + "%s%s%s+0x%" PRIx64, + color_symbol_ptr(), + s->name, + color_normal_ptr(), + (uint64_t) (addr - s->addr)); + + if (offset != NULL) + *offset = addr - s->addr; + if (n_argsp != NULL) + *n_argsp = s->n_args; + + return symbol_buf; + } + + if (addr < s->addr) + highest = ofs - 1; + else + lowest = ofs + 1; + } + } + + /* Not found? Then return NULL. */ + return NULL; +} + + +/* + * get_symbol_name(): + * + * See get_symbol_name_and_n_args(). + */ +char *get_symbol_name(struct symbol_context *sc, uint64_t addr, uint64_t *offs) +{ + return get_symbol_name_and_n_args(sc, addr, offs, NULL); +} + + +/* + * add_symbol_name(): + * + * Add a symbol to the symbol list. + */ +void add_symbol_name(struct symbol_context *sc, + uint64_t addr, uint64_t len, const char *name, int type, int n_args) +{ + struct symbol *s; + + if (sc->sorted_array) { + fprintf(stderr, "add_symbol_name(): Internal error: the " + "symbol array is already sorted\n"); + exit(1); + } + + if (name == NULL) { + fprintf(stderr, "add_symbol_name(): name = NULL\n"); + exit(1); + } + + if (addr == 0 && strcmp(name, "_DYNAMIC_LINK") == 0) + return; + + if (name[0] == '\0') + return; + + /* TODO: Maybe this should be optional? */ + if (name[0] == '.' || name[0] == '$') + return; + + /* Quick test-hack: */ + if (n_args < 0) { + if (strcmp(name, "strlen") == 0) + n_args = 1; + if (strcmp(name, "strcmp") == 0) + n_args = 2; + if (strcmp(name, "strcpy") == 0) + n_args = 2; + if (strcmp(name, "strncpy") == 0) + n_args = 3; + if (strcmp(name, "strlcpy") == 0) + n_args = 3; + if (strcmp(name, "strlcat") == 0) + n_args = 3; + if (strcmp(name, "strncmp") == 0) + n_args = 3; + if (strcmp(name, "memset") == 0) + n_args = 3; + if (strcmp(name, "memcpy") == 0) + n_args = 3; + if (strcmp(name, "bzero") == 0) + n_args = 2; + if (strcmp(name, "bcopy") == 0) + n_args = 3; + } + + if ((addr >> 32) == 0 && (addr & 0x80000000ULL)) + addr |= 0xffffffff00000000ULL; + + CHECK_ALLOCATION(s = (struct symbol *) malloc(sizeof(struct symbol))); + memset(s, 0, sizeof(struct symbol)); + + s->name = symbol_demangle_cplusplus(name); + + if (s->name == NULL) + CHECK_ALLOCATION(s->name = strdup(name)); + + s->addr = addr; + s->len = len; + s->type = type; + s->n_args = n_args; + + sc->n_symbols ++; + + /* Add first in list: */ + s->next = sc->first_symbol; + sc->first_symbol = s; +} + + +/* + * symbol_readfile(): + * + * Read 'nm -S' style symbols from a file. + * + * TODO: This function is an ugly hack, and should be replaced + * with something that reads symbols directly from the executable + * images. + */ +void symbol_readfile(struct symbol_context *sc, char *fname) +{ + FILE *f; + char b1[80]; uint64_t addr; + char b2[80]; uint64_t len; + char b3[80]; int type; + char b4[80]; + int cur_n_symbols = sc->n_symbols; + + f = fopen(fname, "r"); + if (f == NULL) { + perror(fname); + exit(1); + } + + while (!feof(f)) { + memset(b1, 0, sizeof(b1)); + memset(b2, 0, sizeof(b2)); + memset(b3, 0, sizeof(b3)); + memset(b4, 0, sizeof(b4)); + if (fscanf(f, "%s %s\n", b1,b2) != 2) + fprintf(stderr, "warning: symbol file parse error\n"); + if (strlen(b2) < 2 && !(b2[0]>='0' && b2[0]<='9')) { + strlcpy(b3, b2, sizeof(b3)); + strlcpy(b2, "0", sizeof(b2)); + if (fscanf(f, "%s\n", b4) != 1) + fprintf(stderr, "warning: symbol file parse error\n"); + } else { + if (fscanf(f, "%s %s\n", b3,b4) != 2) + fprintf(stderr, "warning: symbol file parse error\n"); + } + + /* printf("b1='%s' b2='%s' b3='%s' b4='%s'\n", + b1,b2,b3,b4); */ + addr = strtoull(b1, NULL, 16); + len = strtoull(b2, NULL, 16); + type = b3[0]; + /* printf("addr=%016" PRIx64" len=%016" PRIx64" type=%i\n", + addr, len, type); */ + + if (type == 't' || type == 'r' || type == 'g') + continue; + + add_symbol_name(sc, addr, len, b4, type, -1); + } + + fclose(f); + + debug("%i symbols\n", sc->n_symbols - cur_n_symbols); +} + + +/* + * sym_addr_compare(): + * + * Helper function for sorting symbols according to their address. + */ +int sym_addr_compare(const void *a, const void *b) +{ + struct symbol *p1 = (struct symbol *) a; + struct symbol *p2 = (struct symbol *) b; + + if (p1->addr < p2->addr) + return -1; + if (p1->addr > p2->addr) + return 1; + + return 0; +} + + +/* + * symbol_recalc_sizes(): + * + * Recalculate sizes of symbols that have size = 0, by creating an array + * containing all symbols, qsort()-ing that array according to address, and + * recalculating the size fields if necessary. + */ +void symbol_recalc_sizes(struct symbol_context *sc) +{ + struct symbol *tmp_array; + struct symbol *last_ptr; + struct symbol *tmp_ptr; + int i; + + CHECK_ALLOCATION(tmp_array = (struct symbol *) malloc(sizeof (struct symbol) * + sc->n_symbols)); + + /* Copy first_symbol --> tmp_array, and remove the old + first_symbol at the same time: */ + tmp_ptr = sc->first_symbol; + i = 0; + while (tmp_ptr != NULL) { + tmp_array[i] = *tmp_ptr; + last_ptr = tmp_ptr; + tmp_ptr = tmp_ptr->next; + free(last_ptr); + i++; + } + + qsort(tmp_array, sc->n_symbols, sizeof(struct symbol), + sym_addr_compare); + sc->sorted_array = 1; + + /* Recreate the first_symbol chain: */ + sc->first_symbol = NULL; + for (i=0; in_symbols; i++) { + /* Recalculate size, if 0: */ + if (tmp_array[i].len == 0) { + uint64_t len; + if (i != sc->n_symbols-1) + len = tmp_array[i+1].addr + - tmp_array[i].addr; + else + len = 1; + + tmp_array[i].len = len; + } + + tmp_array[i].next = &tmp_array[i+1]; + } + + sc->first_symbol = tmp_array; +} + + +/* + * symbol_init(): + * + * Initialize the symbol hashtables. + */ +void symbol_init(struct symbol_context *sc) +{ + sc->first_symbol = NULL; + sc->sorted_array = 0; + sc->n_symbols = 0; +} + diff -Nru gxemul-0.6.2/src/symbol/symbol.cc gxemul-0.7.0+dfsg/src/symbol/symbol.cc --- gxemul-0.6.2/src/symbol/symbol.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/symbol/symbol.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,421 +0,0 @@ -/* - * Copyright (C) 2003-2009 Anders Gavare. 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. The name of the author 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. - * - * - * Address to symbol translation routines. - * - * This module is (probably) independent from the rest of the emulator. - * symbol_init() must be called before any other function in this file is used. - */ - -#include -#include -#include - -#include "symbol.h" - - -#define SYMBOLBUF_MAX 100 - - -/* - * symbol_nsymbols(): - * - * Return n_symbols. - */ -int symbol_nsymbols(struct symbol_context *sc) -{ - return sc->n_symbols; -} - - -/* - * get_symbol_addr(): - * - * Find a symbol by name. If addr is non-NULL, *addr is set to the symbol's - * address. Return value is 1 if the symbol is found, 0 otherwise. - * - * NOTE: This is O(n). - */ -int get_symbol_addr(struct symbol_context *sc, const char *symbol, uint64_t *addr) -{ - struct symbol *s; - - if (sc->sorted_array) { - int i; - for (i=0; in_symbols; i++) - if (strcmp(symbol, sc->first_symbol[i].name) == 0) { - if (addr != NULL) - *addr = sc->first_symbol[i].addr; - return 1; - } - } else { - s = sc->first_symbol; - while (s != NULL) { - if (strcmp(symbol, s->name) == 0) { - if (addr != NULL) - *addr = s->addr; - return 1; - } - s = s->next; - } - } - - return 0; -} - - -/* - * get_symbol_name_and_n_args(): - * - * Translate an address into a symbol name. The return value is a pointer - * to a static char array, containing the symbol name. (In other words, - * this function is not reentrant. This removes the need for memory allocation - * at the caller's side.) - * - * If offset is not a NULL pointer, *offset is set to the offset within - * the symbol. For example, if there is a symbol at address 0x1000 with - * length 0x100, and a caller wants to know the symbol name of address - * 0x1008, the symbol's name will be found in the static char array, and - * *offset will be set to 0x8. - * - * If n_argsp is non-NULL, *n_argsp is set to the symbol's n_args value. - * - * If no symbol was found, NULL is returned instead. - */ -static char symbol_buf[SYMBOLBUF_MAX+1]; -char *get_symbol_name_and_n_args(struct symbol_context *sc, uint64_t addr, - uint64_t *offset, int *n_argsp) -{ - struct symbol *s; - - if (sc->n_symbols == 0) - return NULL; - - if ((addr >> 32) == 0 && (addr & 0x80000000ULL)) - addr |= 0xffffffff00000000ULL; - - symbol_buf[0] = symbol_buf[SYMBOLBUF_MAX] = '\0'; - if (offset != NULL) - *offset = 0; - - if (!sc->sorted_array) { - /* Slow, linear O(n) search: */ - s = sc->first_symbol; - while (s != NULL) { - /* Found a match? */ - if (addr >= s->addr && addr < s->addr + s->len) { - if (addr == s->addr) - snprintf(symbol_buf, SYMBOLBUF_MAX, - "%s", s->name); - else - snprintf(symbol_buf, SYMBOLBUF_MAX, - "%s+0x%" PRIx64, s->name, (uint64_t) - (addr - s->addr)); - if (offset != NULL) - *offset = addr - s->addr; - if (n_argsp != NULL) - *n_argsp = s->n_args; - return symbol_buf; - } - s = s->next; - } - } else { - /* Faster, O(log n) search: */ - int lowest = 0, highest = sc->n_symbols - 1; - while (lowest <= highest) { - int ofs = (lowest + highest) / 2; - s = sc->first_symbol + ofs; - - /* Found a match? */ - if (addr >= s->addr && addr <= s->addr + (s->len - 1)) { - if (addr == s->addr) - snprintf(symbol_buf, SYMBOLBUF_MAX, - "%s", s->name); - else - snprintf(symbol_buf, SYMBOLBUF_MAX, - "%s+0x%" PRIx64, s->name, (uint64_t) - (addr - s->addr)); - - if (offset != NULL) - *offset = addr - s->addr; - if (n_argsp != NULL) - *n_argsp = s->n_args; - - return symbol_buf; - } - - if (addr < s->addr) - highest = ofs - 1; - else - lowest = ofs + 1; - } - } - - /* Not found? Then return NULL. */ - return NULL; -} - - -/* - * get_symbol_name(): - * - * See get_symbol_name_and_n_args(). - */ -char *get_symbol_name(struct symbol_context *sc, uint64_t addr, uint64_t *offs) -{ - return get_symbol_name_and_n_args(sc, addr, offs, NULL); -} - - -/* - * add_symbol_name(): - * - * Add a symbol to the symbol list. - */ -void add_symbol_name(struct symbol_context *sc, - uint64_t addr, uint64_t len, const char *name, int type, int n_args) -{ - struct symbol *s; - - if (sc->sorted_array) { - fprintf(stderr, "add_symbol_name(): Internal error: the " - "symbol array is already sorted\n"); - exit(1); - } - - if (name == NULL) { - fprintf(stderr, "add_symbol_name(): name = NULL\n"); - exit(1); - } - - if (addr == 0 && strcmp(name, "_DYNAMIC_LINK") == 0) - return; - - if (name[0] == '\0') - return; - - /* TODO: Maybe this should be optional? */ - if (name[0] == '.' || name[0] == '$') - return; - - /* Quick test-hack: */ - if (n_args < 0) { - if (strcmp(name, "strlen") == 0) - n_args = 1; - if (strcmp(name, "strcmp") == 0) - n_args = 2; - if (strcmp(name, "strcpy") == 0) - n_args = 2; - if (strcmp(name, "strncpy") == 0) - n_args = 3; - if (strcmp(name, "strlcpy") == 0) - n_args = 3; - if (strcmp(name, "strlcat") == 0) - n_args = 3; - if (strcmp(name, "strncmp") == 0) - n_args = 3; - if (strcmp(name, "memset") == 0) - n_args = 3; - if (strcmp(name, "memcpy") == 0) - n_args = 3; - if (strcmp(name, "bzero") == 0) - n_args = 2; - if (strcmp(name, "bcopy") == 0) - n_args = 3; - } - - if ((addr >> 32) == 0 && (addr & 0x80000000ULL)) - addr |= 0xffffffff00000000ULL; - - CHECK_ALLOCATION(s = (struct symbol *) malloc(sizeof(struct symbol))); - memset(s, 0, sizeof(struct symbol)); - - s->name = symbol_demangle_cplusplus(name); - - if (s->name == NULL) - CHECK_ALLOCATION(s->name = strdup(name)); - - s->addr = addr; - s->len = len; - s->type = type; - s->n_args = n_args; - - sc->n_symbols ++; - - /* Add first in list: */ - s->next = sc->first_symbol; - sc->first_symbol = s; -} - - -/* - * symbol_readfile(): - * - * Read 'nm -S' style symbols from a file. - * - * TODO: This function is an ugly hack, and should be replaced - * with something that reads symbols directly from the executable - * images. - */ -void symbol_readfile(struct symbol_context *sc, char *fname) -{ - FILE *f; - char b1[80]; uint64_t addr; - char b2[80]; uint64_t len; - char b3[80]; int type; - char b4[80]; - int cur_n_symbols = sc->n_symbols; - - f = fopen(fname, "r"); - if (f == NULL) { - perror(fname); - exit(1); - } - - while (!feof(f)) { - memset(b1, 0, sizeof(b1)); - memset(b2, 0, sizeof(b2)); - memset(b3, 0, sizeof(b3)); - memset(b4, 0, sizeof(b4)); - if (fscanf(f, "%s %s\n", b1,b2) != 2) - fprintf(stderr, "warning: symbol file parse error\n"); - if (strlen(b2) < 2 && !(b2[0]>='0' && b2[0]<='9')) { - strlcpy(b3, b2, sizeof(b3)); - strlcpy(b2, "0", sizeof(b2)); - if (fscanf(f, "%s\n", b4) != 1) - fprintf(stderr, "warning: symbol file parse error\n"); - } else { - if (fscanf(f, "%s %s\n", b3,b4) != 2) - fprintf(stderr, "warning: symbol file parse error\n"); - } - - /* printf("b1='%s' b2='%s' b3='%s' b4='%s'\n", - b1,b2,b3,b4); */ - addr = strtoull(b1, NULL, 16); - len = strtoull(b2, NULL, 16); - type = b3[0]; - /* printf("addr=%016" PRIx64" len=%016" PRIx64" type=%i\n", - addr, len, type); */ - - if (type == 't' || type == 'r' || type == 'g') - continue; - - add_symbol_name(sc, addr, len, b4, type, -1); - } - - fclose(f); - - debug("%i symbols\n", sc->n_symbols - cur_n_symbols); -} - - -/* - * sym_addr_compare(): - * - * Helper function for sorting symbols according to their address. - */ -int sym_addr_compare(const void *a, const void *b) -{ - struct symbol *p1 = (struct symbol *) a; - struct symbol *p2 = (struct symbol *) b; - - if (p1->addr < p2->addr) - return -1; - if (p1->addr > p2->addr) - return 1; - - return 0; -} - - -/* - * symbol_recalc_sizes(): - * - * Recalculate sizes of symbols that have size = 0, by creating an array - * containing all symbols, qsort()-ing that array according to address, and - * recalculating the size fields if necessary. - */ -void symbol_recalc_sizes(struct symbol_context *sc) -{ - struct symbol *tmp_array; - struct symbol *last_ptr; - struct symbol *tmp_ptr; - int i; - - CHECK_ALLOCATION(tmp_array = (struct symbol *) malloc(sizeof (struct symbol) * - sc->n_symbols)); - - /* Copy first_symbol --> tmp_array, and remove the old - first_symbol at the same time: */ - tmp_ptr = sc->first_symbol; - i = 0; - while (tmp_ptr != NULL) { - tmp_array[i] = *tmp_ptr; - last_ptr = tmp_ptr; - tmp_ptr = tmp_ptr->next; - free(last_ptr); - i++; - } - - qsort(tmp_array, sc->n_symbols, sizeof(struct symbol), - sym_addr_compare); - sc->sorted_array = 1; - - /* Recreate the first_symbol chain: */ - sc->first_symbol = NULL; - for (i=0; in_symbols; i++) { - /* Recalculate size, if 0: */ - if (tmp_array[i].len == 0) { - uint64_t len; - if (i != sc->n_symbols-1) - len = tmp_array[i+1].addr - - tmp_array[i].addr; - else - len = 1; - - tmp_array[i].len = len; - } - - tmp_array[i].next = &tmp_array[i+1]; - } - - sc->first_symbol = tmp_array; -} - - -/* - * symbol_init(): - * - * Initialize the symbol hashtables. - */ -void symbol_init(struct symbol_context *sc) -{ - sc->first_symbol = NULL; - sc->sorted_array = 0; - sc->n_symbols = 0; -} - diff -Nru gxemul-0.6.2/src/symbol/symbol_demangle.c gxemul-0.7.0+dfsg/src/symbol/symbol_demangle.c --- gxemul-0.6.2/src/symbol/symbol_demangle.c 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/symbol/symbol_demangle.c 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2006-2009 Anders Gavare. 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. The name of the author 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. + * + * + * C++ symbol name demangling. + * + * For obvious performance reasons, the external c++filt utility cannot be + * used. Also, the host's version of this utility might be incompatible with + * the binary being emulated. + * + * TODO: Constructors, destructors, and lots of other stuff. See + * http://www.codesourcery.com/cxx-abi/abi.html#mangling for details. + */ + +#include +#include +#include +#include + +#include "symbol.h" + + +#define MAXLEN 1000 + + +static void add_string(char *p, size_t *curlenp, const char *to_add) +{ + size_t curlen = *curlenp; + while (curlen < MAXLEN && *to_add) + p[curlen++] = *to_add++; + *curlenp = curlen; +} + + +/* + * symbol_demangle_cplusplus_nested(): + * + * Try to demangle a nested cplusplus name. name points to the first character + * after "_ZN". + */ +static char *symbol_demangle_cplusplus_nested(const char *name) +{ + char *result; + size_t result_len = 0, len; + int first = 1, type_added = 0, pointercounter, reference; + + CHECK_ALLOCATION(result = (char *) malloc(MAXLEN + 1)); + result[0] = '\0'; + + while (name[0] && name[0] != 'E' && result_len < MAXLEN) { + /* Read length of the next part: */ + len = 0; + if (*name == '0') { + name ++; + } else { + while (isdigit((int)*name)) { + len *= 10; + len += (*name - '0'); + name ++; + } + } + + /* Add :: */ + if (!first) + add_string(result, &result_len, "::"); + + /* Read the part itself: */ + while (len-- >= 1 && result_len < MAXLEN) + result[result_len ++] = *name++; + + first = 0; + } + + if (name[0] != 'E') + goto fail; + + name ++; + + if (*name) + add_string(result, &result_len, "{"); + + /* Type: */ + pointercounter = reference = 0; + while (*name) { + int argument_done = 0; + char t = *name++; + switch (t) { + case 'c': + add_string(result, &result_len, "char"); + argument_done = 1; + break; + case 'a': + add_string(result, &result_len, "signed char"); + argument_done = 1; + break; + case 'h': + add_string(result, &result_len, "unsigned char"); + argument_done = 1; + break; + case 'i': + add_string(result, &result_len, "int"); + argument_done = 1; + break; + case 'j': + add_string(result, &result_len, "unsigned int"); + argument_done = 1; + break; + case 'w': + add_string(result, &result_len, "wchar_t"); + argument_done = 1; + break; + case 'b': + add_string(result, &result_len, "bool"); + argument_done = 1; + break; + case 's': + add_string(result, &result_len, "short"); + argument_done = 1; + break; + case 't': + add_string(result, &result_len, "unsigned short"); + argument_done = 1; + break; + case 'l': + add_string(result, &result_len, "long"); + argument_done = 1; + break; + case 'm': + add_string(result, &result_len, "unsigned long"); + argument_done = 1; + break; + case 'x': + add_string(result, &result_len, "long long"); + argument_done = 1; + break; + case 'y': + add_string(result, &result_len, "unsigned long long"); + argument_done = 1; + break; + case 'n': + add_string(result, &result_len, "__int128"); + argument_done = 1; + break; + case 'o': + add_string(result, &result_len, "unsigned __int128"); + argument_done = 1; + break; + case 'f': + add_string(result, &result_len, "float"); + argument_done = 1; + break; + case 'd': + add_string(result, &result_len, "double"); + argument_done = 1; + break; + case 'e': + add_string(result, &result_len, "__float80"); + argument_done = 1; + break; + case 'g': + add_string(result, &result_len, "__float128"); + argument_done = 1; + break; + case 'z': + add_string(result, &result_len, "..."); + argument_done = 1; + break; + case 'P': + pointercounter ++; + break; + case 'R': + reference ++; + break; + case 'v': /* void */ + break; + default:/* Unknown */ + goto fail; + } + if (argument_done) { + while (pointercounter-- > 0) + add_string(result, &result_len, "*"); + while (reference-- > 0) + add_string(result, &result_len, "&"); + if (*name) + add_string(result, &result_len, ","); + } + type_added = 1; + } + + if (type_added) + add_string(result, &result_len, "}"); + + if (result_len == MAXLEN) + goto fail; + + result[result_len] = '\0'; + + return result; + +fail: + free(result); + return NULL; +} + + +/* + * symbol_demangle_cplusplus(): + * + * Try to demangle name. If name was not a valid/known C++ symbol, then NULL + * is returned. Otherwise, a newly allocated string is returned, containing + * the demangled name. + */ +char *symbol_demangle_cplusplus(const char *name) +{ + /* Only support _Z-style mangled names, for now: */ + if (strlen(name) < 2 || name[0] != '_' || name[1] != 'Z') + return NULL; + + name += 2; + + switch (name[0]) { + case 'N': + return symbol_demangle_cplusplus_nested(name + 1); + break; + } + + return NULL; +} + + + +#ifdef TEST + +void test(char *mangled, char *result) +{ + char *p = symbol_demangle_cplusplus(mangled); + if (p == NULL) { + if (result == NULL) { + return; + } else { + printf("FAILURE for %s!\n", mangled); + exit(1); + } + } + if (strcmp(p, result) == 0) + return; + printf("FAILURE for %s! (result = %s)\n", mangled, p); + exit(1); +} + +int main(int argc, char *argv[]) +{ + test("monkey", NULL); + test("_monkey", NULL); + test("_zmonkey", NULL); + test("_Zmonkey", NULL); + test("_ZQ5abcde", NULL); + test("_ZN3abc5defghE", "abc::defgh"); + test("_ZN05defghEv", "::defgh{}"); + test("_ZN5defghEv", "defgh{}"); + test("_ZN3abc5defghEv", "abc::defgh{}"); + test("_ZN3abc5defghEc", "abc::defgh{char}"); + test("_ZN1a2bcEjij", "a::bc{unsigned int,int,unsigned int}"); + printf("OK\n"); + return 0; +} + +#endif + diff -Nru gxemul-0.6.2/src/symbol/symbol_demangle.cc gxemul-0.7.0+dfsg/src/symbol/symbol_demangle.cc --- gxemul-0.6.2/src/symbol/symbol_demangle.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/symbol/symbol_demangle.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2006-2009 Anders Gavare. 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. The name of the author 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. - * - * - * C++ symbol name demangling. - * - * For obvious performance reasons, the external c++filt utility cannot be - * used. Also, the host's version of this utility might be incompatible with - * the binary being emulated. - * - * TODO: Constructors, destructors, and lots of other stuff. See - * http://www.codesourcery.com/cxx-abi/abi.html#mangling for details. - */ - -#include -#include -#include -#include - -#include "symbol.h" - - -#define MAXLEN 1000 - - -static void add_string(char *p, size_t *curlenp, const char *to_add) -{ - size_t curlen = *curlenp; - while (curlen < MAXLEN && *to_add) - p[curlen++] = *to_add++; - *curlenp = curlen; -} - - -/* - * symbol_demangle_cplusplus_nested(): - * - * Try to demangle a nested cplusplus name. name points to the first character - * after "_ZN". - */ -static char *symbol_demangle_cplusplus_nested(const char *name) -{ - char *result; - size_t result_len = 0, len; - int first = 1, type_added = 0, pointercounter, reference; - - CHECK_ALLOCATION(result = (char *) malloc(MAXLEN + 1)); - result[0] = '\0'; - - while (name[0] && name[0] != 'E' && result_len < MAXLEN) { - /* Read length of the next part: */ - len = 0; - if (*name == '0') { - name ++; - } else { - while (isdigit((int)*name)) { - len *= 10; - len += (*name - '0'); - name ++; - } - } - - /* Add :: */ - if (!first) - add_string(result, &result_len, "::"); - - /* Read the part itself: */ - while (len-- >= 1 && result_len < MAXLEN) - result[result_len ++] = *name++; - - first = 0; - } - - if (name[0] != 'E') - goto fail; - - name ++; - - if (*name) - add_string(result, &result_len, "{"); - - /* Type: */ - pointercounter = reference = 0; - while (*name) { - int argument_done = 0; - char t = *name++; - switch (t) { - case 'c': - add_string(result, &result_len, "char"); - argument_done = 1; - break; - case 'a': - add_string(result, &result_len, "signed char"); - argument_done = 1; - break; - case 'h': - add_string(result, &result_len, "unsigned char"); - argument_done = 1; - break; - case 'i': - add_string(result, &result_len, "int"); - argument_done = 1; - break; - case 'j': - add_string(result, &result_len, "unsigned int"); - argument_done = 1; - break; - case 'w': - add_string(result, &result_len, "wchar_t"); - argument_done = 1; - break; - case 'b': - add_string(result, &result_len, "bool"); - argument_done = 1; - break; - case 's': - add_string(result, &result_len, "short"); - argument_done = 1; - break; - case 't': - add_string(result, &result_len, "unsigned short"); - argument_done = 1; - break; - case 'l': - add_string(result, &result_len, "long"); - argument_done = 1; - break; - case 'm': - add_string(result, &result_len, "unsigned long"); - argument_done = 1; - break; - case 'x': - add_string(result, &result_len, "long long"); - argument_done = 1; - break; - case 'y': - add_string(result, &result_len, "unsigned long long"); - argument_done = 1; - break; - case 'n': - add_string(result, &result_len, "__int128"); - argument_done = 1; - break; - case 'o': - add_string(result, &result_len, "unsigned __int128"); - argument_done = 1; - break; - case 'f': - add_string(result, &result_len, "float"); - argument_done = 1; - break; - case 'd': - add_string(result, &result_len, "double"); - argument_done = 1; - break; - case 'e': - add_string(result, &result_len, "__float80"); - argument_done = 1; - break; - case 'g': - add_string(result, &result_len, "__float128"); - argument_done = 1; - break; - case 'z': - add_string(result, &result_len, "..."); - argument_done = 1; - break; - case 'P': - pointercounter ++; - break; - case 'R': - reference ++; - break; - case 'v': /* void */ - break; - default:/* Unknown */ - goto fail; - } - if (argument_done) { - while (pointercounter-- > 0) - add_string(result, &result_len, "*"); - while (reference-- > 0) - add_string(result, &result_len, "&"); - if (*name) - add_string(result, &result_len, ","); - } - type_added = 1; - } - - if (type_added) - add_string(result, &result_len, "}"); - - if (result_len == MAXLEN) - goto fail; - - result[result_len] = '\0'; - - return result; - -fail: - free(result); - return NULL; -} - - -/* - * symbol_demangle_cplusplus(): - * - * Try to demangle name. If name was not a valid/known C++ symbol, then NULL - * is returned. Otherwise, a newly allocated string is returned, containing - * the demangled name. - */ -char *symbol_demangle_cplusplus(const char *name) -{ - /* Only support _Z-style mangled names, for now: */ - if (strlen(name) < 2 || name[0] != '_' || name[1] != 'Z') - return NULL; - - name += 2; - - switch (name[0]) { - case 'N': - return symbol_demangle_cplusplus_nested(name + 1); - break; - } - - return NULL; -} - - - -#ifdef TEST - -void test(char *mangled, char *result) -{ - char *p = symbol_demangle_cplusplus(mangled); - if (p == NULL) { - if (result == NULL) { - return; - } else { - printf("FAILURE for %s!\n", mangled); - exit(1); - } - } - if (strcmp(p, result) == 0) - return; - printf("FAILURE for %s! (result = %s)\n", mangled, p); - exit(1); -} - -int main(int argc, char *argv[]) -{ - test("monkey", NULL); - test("_monkey", NULL); - test("_zmonkey", NULL); - test("_Zmonkey", NULL); - test("_ZQ5abcde", NULL); - test("_ZN3abc5defghE", "abc::defgh"); - test("_ZN05defghEv", "::defgh{}"); - test("_ZN5defghEv", "defgh{}"); - test("_ZN3abc5defghEv", "abc::defgh{}"); - test("_ZN3abc5defghEc", "abc::defgh{char}"); - test("_ZN1a2bcEjij", "a::bc{unsigned int,int,unsigned int}"); - printf("OK\n"); - return 0; -} - -#endif - diff -Nru gxemul-0.6.2/src/ui/console/ConsoleUI.cc gxemul-0.7.0+dfsg/src/ui/console/ConsoleUI.cc --- gxemul-0.6.2/src/ui/console/ConsoleUI.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/ui/console/ConsoleUI.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2007-2019 Anders Gavare. 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. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include - -#include "misc.h" -#include "ConsoleUI.h" -#include "GXemul.h" - - -ConsoleUI::ConsoleUI(GXemul *gxemul) - : UI(gxemul) - , m_consoleIsInitialized(false) -{ -} - - -ConsoleUI::~ConsoleUI() -{ - // Restore the terminal mode: - if (m_consoleIsInitialized) - tcsetattr(STDIN_FILENO, TCSANOW, &m_oldTermios); -} - - -// Note: Use of global GXemul pointer! -static GXemul* g_GXemul; -static struct termios g_curTermios; - -static void ReshowCurrentCommandBuffer() -{ - if (g_GXemul->GetRunState() == GXemul::Paused) { - // Reshow the prompt and the current command line: - g_GXemul->GetCommandInterpreter().ReshowCurrentCommandBuffer(); - std::cout.flush(); - } -} - -/** - * \brief CTRL-C handler which sets the run state to Paused. - */ -extern "C" void ConsoleUI_SIGINT_Handler(int n) -{ - if (g_GXemul->IsInterrupting()) - std::cout << "^C (already attempting to interrupt, please wait)\n"; - else - std::cout << "^C\n"; - - g_GXemul->Interrupt(); - - g_GXemul->GetCommandInterpreter().ClearCurrentCommandBuffer(); - ReshowCurrentCommandBuffer(); - - signal(SIGINT, ConsoleUI_SIGINT_Handler); -} - -/** - * \brief Restore terminal settings after a CTRL-Z. - * - * If the user presses CTRL-Z (to stop the emulator process) and then - * continues, the termios settings might have been invalidated. This - * function restores them. - */ -extern "C" void ConsoleUI_SIGCONT_Handler(int n) -{ - tcsetattr(STDIN_FILENO, TCSANOW, &g_curTermios); - ReshowCurrentCommandBuffer(); - signal(SIGCONT, ConsoleUI_SIGCONT_Handler); -} - - -void ConsoleUI::Initialize() -{ - if (m_consoleIsInitialized) - return; - - tcgetattr(STDIN_FILENO, &m_oldTermios); - m_currentTermios = m_oldTermios; - - // Set the terminal mode: - m_currentTermios.c_lflag &= ~ICANON; - m_currentTermios.c_cc[VTIME] = 0; - m_currentTermios.c_cc[VMIN] = 1; - m_currentTermios.c_lflag &= ~ECHO; - - tcsetattr(STDIN_FILENO, TCSANOW, &m_currentTermios); - - // Signal handlers for CTRL-C and CTRL-Z. - // Note: Using a global GXemul instance pointer! - g_GXemul = m_gxemul; - g_curTermios = m_currentTermios; - signal(SIGINT, ConsoleUI_SIGINT_Handler); - signal(SIGCONT, ConsoleUI_SIGCONT_Handler); - - m_consoleIsInitialized = true; -} - - -void ConsoleUI::UpdateUI() -{ - // Empty. -} - - -void ConsoleUI::ShowStartupBanner() -{ - std::cout << GXemul::Version() << "\n"; -} - - -static vector SplitIntoRows(const string &msg, bool addEmptyLines) -{ - // This is slow and hackish, but works. - vector result; - string line; - - for (size_t i=0, n=msg.length(); i 0 || addEmptyLines) - result.push_back(line); - line = ""; - } else { - line += ch; - } - } - - if (line.length() > 0) - result.push_back(line); - - return result; -} - - -void ConsoleUI::ShowDebugMessage(const string& msg) -{ - vector lines = SplitIntoRows(msg, true); - - for (size_t i=0; iGetRunState() == GXemul::Running) { - if (isatty(fileno(stdout))) - std::cout << "\e[1m" << m_indentationMsg << lines[i] << "\e[0m\n"; - else - std::cout << "[ " << m_indentationMsg << lines[i] << " ]\n"; - } else { - std::cout << m_indentationMsg << lines[i] << "\n"; - } - - // Replace indentation string with spaces after first - // line of output: - for (size_t j=m_indentationMsg.length(); j>0; --j) - m_indentationMsg[j-1] = ' '; - } - - std::cout.flush(); -} - - -void ConsoleUI::ShowDebugMessage(Component* component, const string& msg) -{ - if (m_gxemul->GetQuietMode()) - return; - - stringstream ss; - string componentName = component->GenerateShortestPossiblePath(); - - vector lines = SplitIntoRows(msg, false); - - // cpu0: blahlonger - // blahshort - size_t i; - string spaces = ""; - for (i=0; i " << inputline << " \rGXemul> "; - - for (size_t pos = 0; pos < cursorPosition; pos++) - std::cout << (string() + inputline[pos]); - - std::cout.flush(); -} - - -/** - * \brief Read a key from stdin, blocking. - * - * @return The key read from stdin. - */ -static stringchar ReadKey() -{ - return std::cin.get(); -} - - -void ConsoleUI::ReadAndExecuteCommand() -{ - // Initial dummy addkey, to show the input line with the prompt, etc.: - m_gxemul->GetCommandInterpreter().AddKey('\0'); - - while (!m_gxemul->GetCommandInterpreter().AddKey(ReadKey())) - ; -} - - -void ConsoleUI::InputLineDone() -{ - std::cout << "\n"; - std::cout.flush(); -} - - -void ConsoleUI::Shutdown() -{ -} - - -int ConsoleUI::MainLoop() -{ - GXemul::RunState oldRunState = m_gxemul->GetRunState(); - - while (m_gxemul->GetRunState() != GXemul::Quitting) { - GXemul::RunState runState = m_gxemul->GetRunState(); - - switch (runState) { - - case GXemul::SingleStepping: - case GXemul::Running: - // Switching from Paused state to running? Then - // we need to: - // 1) flush old cached state - // 2) perform pre-run checks. - if (oldRunState == GXemul::Paused) { - m_gxemul->GetRootComponent()->FlushCachedState(); - - if (!m_gxemul->GetRootComponent()->PreRunCheck(m_gxemul)) { - FatalError("Pre-run check failed.\n"); - m_gxemul->SetRunState(GXemul::Paused); - runState = m_gxemul->GetRunState(); - break; - } - } - - m_gxemul->Execute(); - break; - - case GXemul::Quitting: - break; - - case GXemul::Paused: - // When issuing interactive commands, "anything" can - // happen to the component tree, and thus any cached - // state quickly becomes untrustworthy. Let's flush it. - m_gxemul->GetRootComponent()->FlushCachedState(); - - ReadAndExecuteCommand(); - break; - } - - oldRunState = runState; - } - - return 0; -} - diff -Nru gxemul-0.6.2/src/ui/console/Makefile.skel gxemul-0.7.0+dfsg/src/ui/console/Makefile.skel --- gxemul-0.6.2/src/ui/console/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/ui/console/Makefile.skel 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -# -# Makefile for GXemul src/ui/console -# - -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) -LIBS=$(OTHERLIBS) - -OBJS=ConsoleUI.o - -all: $(OBJS) - -$(OBJS): Makefile - -clean: - rm -f $(OBJS) *core - -clean_all: clean - rm -f Makefile - diff -Nru gxemul-0.6.2/src/ui/Makefile.skel gxemul-0.7.0+dfsg/src/ui/Makefile.skel --- gxemul-0.6.2/src/ui/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/ui/Makefile.skel 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# -# Makefile for GXemul src/ui -# - -all: do_console do_nullui - -$(OBJS): Makefile - -do_console: - cd console; $(MAKE) - -do_nullui: - cd nullui; $(MAKE) - -clean: - cd console; $(MAKE) clean - cd nullui; $(MAKE) clean - rm -f $(OBJS) *core - -clean_all: clean - cd console; $(MAKE) clean_all - cd nullui; $(MAKE) clean_all - rm -f Makefile - diff -Nru gxemul-0.6.2/src/ui/nullui/Makefile.skel gxemul-0.7.0+dfsg/src/ui/nullui/Makefile.skel --- gxemul-0.6.2/src/ui/nullui/Makefile.skel 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/ui/nullui/Makefile.skel 1970-01-01 00:00:00.000000000 +0000 @@ -1,19 +0,0 @@ -# -# Makefile for GXemul src/ui/nullui -# - -CXXFLAGS=$(CWARNINGS) $(COPTIM) $(CPEDANTIC) $(INCLUDE2) -LIBS=$(OTHERLIBS) - -OBJS=NullUI.o - -all: $(OBJS) - -$(OBJS): Makefile - -clean: - rm -f $(OBJS) *core - -clean_all: clean - rm -f Makefile - diff -Nru gxemul-0.6.2/src/ui/nullui/NullUI.cc gxemul-0.7.0+dfsg/src/ui/nullui/NullUI.cc --- gxemul-0.6.2/src/ui/nullui/NullUI.cc 2019-06-22 18:23:27.000000000 +0000 +++ gxemul-0.7.0+dfsg/src/ui/nullui/NullUI.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008-2010 Anders Gavare. 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. The name of the author 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 "NullUI.h" -#include "GXemul.h" - - -NullUI::NullUI(GXemul *gxemul) - : UI(gxemul) -{ -} - - -NullUI::~NullUI() -{ -} - - -void NullUI::Initialize() -{ -} - - -void NullUI::ShowStartupBanner() -{ -} - - -void NullUI::UpdateUI() -{ -} - - -void NullUI::ShowDebugMessage(const string& msg) -{ -} - - -void NullUI::ShowDebugMessage(Component* component, const string& msg) -{ -} - - -void NullUI::ShowCommandMessage(const string& command) -{ -} - - -void NullUI::FatalError(const string& msg) -{ -} - - -void NullUI::RedisplayInputLine(const string& inputline, size_t cursorPosition) -{ -} - - -void NullUI::InputLineDone() -{ -} - - -void NullUI::Shutdown() -{ -} - - -int NullUI::MainLoop() -{ - return 0; -} - Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/test/FileLoader_A.OUT_M88K and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/test/FileLoader_A.OUT_M88K differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/test/FileLoader_B.OUT_i960 and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/test/FileLoader_B.OUT_i960 differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/test/FileLoader_ELF_MIPS and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/test/FileLoader_ELF_MIPS differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/test/FileLoader_ELF_MIPS16 and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/test/FileLoader_ELF_MIPS16 differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/test/FileLoader_ELF_RISCV64 and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/test/FileLoader_ELF_RISCV64 differ Binary files /tmp/tmpaarp4e17/pWfV7dXnD4/gxemul-0.6.2/test/FileLoader_ELF_SH5 and /tmp/tmpaarp4e17/9kW3MclFqY/gxemul-0.7.0+dfsg/test/FileLoader_ELF_SH5 differ diff -Nru gxemul-0.6.2/test/FileLoader_NonsenseFile gxemul-0.7.0+dfsg/test/FileLoader_NonsenseFile --- gxemul-0.6.2/test/FileLoader_NonsenseFile 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/FileLoader_NonsenseFile 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -This is a nonsense file. diff -Nru gxemul-0.6.2/test/floatingpoint/Makefile gxemul-0.7.0+dfsg/test/floatingpoint/Makefile --- gxemul-0.6.2/test/floatingpoint/Makefile 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/floatingpoint/Makefile 2021-11-27 09:42:23.000000000 +0000 @@ -1,15 +1,61 @@ CFLAGS=-DHOSTNATIVE -I../../src/include/testmachine all: - @echo Read the README file for instructions on how to build - @echo the floatingpoint test program for various targets. + @echo Read the Makefile to see which targets are available. @echo To build for the host, type \"make native\" -native: fptest.o fpconst.o +fptest: fptest.o fpconst.o $(CC) fptest.o fpconst.o -o fptest + +native: clean fptest ./fptest > fptest_hostnative.output cat fptest_hostnative.output clean: rm -f *.o fptest fptest.output *core + +############################################################################## + + +arm: clean + arm-unknown-elf-gcc -I../../src/include/testmachine -g fptest.c -O2 -c -mhard-float + arm-unknown-elf-gcc -I../../src/include/testmachine -g fpconst.c -O2 -c -mhard-float + arm-unknown-elf-ld -e f fptest.o fpconst.o -o fptest + file fptest + ../../gxemul -qE testarm fptest > fptest_arm.output + diff fptest_hostnative.output fptest_arm.output + +mips32: clean + mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fptest.c -O0 -mips1 -mabi=32 -c -G 0 + mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fpconst.c -O0 -mips1 -mabi=32 -c -G 0 + mips64-unknown-elf-ld -Ttext 0x80030000 -e f fptest.o fpconst.o -o fptest + file fptest + ../../gxemul -C 4Kc -qE testmips fptest > fptest_mips32.output + diff fptest_hostnative.output fptest_mips32.output + +mips64: clean + mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fptest.c -O0 -mips4 -mabi=64 -c -G 0 + mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fpconst.c -O0 -mips4 -mabi=64 -c -G 0 + mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f fptest.o fpconst.o -o fptest --oformat=elf64-bigmips + file fptest + ../../gxemul -qE testmips fptest > fptest_mips64.output + diff fptest_hostnative.output fptest_mips64.output + +riscv: clean + riscv64-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fptest.c -c + riscv64-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fpconst.c -c + riscv64-unknown-elf-ld -e _f fptest.o fpconst.o -o fptest + file fptest + ../../gxemul -qE testriscv fptest > fptest_riscv.output + diff fptest_hostnative.output fptest_riscv.output + +sh4: clean + sh4-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fptest.c -c + sh4-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fpconst.c -c + sh4-unknown-elf-ld -e _f fptest.o fpconst.o -o fptest + file fptest + ../../gxemul -qE testsh fptest > fptest_sh4.output + diff fptest_hostnative.output fptest_sh4.output + + diff -Nru gxemul-0.6.2/test/floatingpoint/README gxemul-0.7.0+dfsg/test/floatingpoint/README --- gxemul-0.6.2/test/floatingpoint/README 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/floatingpoint/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -ARM ---- -arm-unknown-elf-gcc -I../../src/include/testmachine -g fptest.c -O2 -c -mhard-float -arm-unknown-elf-gcc -I../../src/include/testmachine -g fpconst.c -O2 -c -mhard-float -arm-unknown-elf-ld -e f fptest.o fpconst.o -o fptest -file fptest -../../gxemul -E testarm fptest > fptest.output -diff fptest_hostnative.output fptest.output - - - -MIPS (64-bit) -------------- -mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fptest.c -O0 -mips4 -mabi=64 -c -G 0 -mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fpconst.c -O0 -mips4 -mabi=64 -c -G 0 -mips64-unknown-elf-ld -Ttext 0xa800000000030000 -e f fptest.o fpconst.o -o fptest --oformat=elf64-bigmips -file fptest -../../gxemul -qE oldtestmips fptest > fptest.output -diff fptest_hostnative.output fptest.output - - -MIPS (32-bit) -------------- -mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fptest.c -O0 -mips1 -mabi=32 -c -G 0 -mips64-unknown-elf-gcc -DMIPS -I../../src/include/testmachine -g fpconst.c -O0 -mips1 -mabi=32 -c -G 0 -mips64-unknown-elf-ld -Ttext 0x80030000 -e f fptest.o fpconst.o -o fptest -file fptest -../../gxemul -C 4Kc -qE oldtestmips fptest > fptest.output -diff fptest_hostnative.output fptest.output - - -SH --- -sh4-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fptest.c -c -sh4-unknown-elf-gcc -I../../src/include/testmachine -O2 -g fpconst.c -c -sh4-unknown-elf-ld -e _f fptest.o fpconst.o -o fptest -file fptest -../../gxemul -E testsh fptest > fptest.output -diff fptest_hostnative.output fptest.output -// TODO: undefined reference to `__fpscr_values' - diff -Nru gxemul-0.6.2/test/test_netbsd8.1_hpcmips_install.expect gxemul-0.7.0+dfsg/test/test_netbsd8.1_hpcmips_install.expect --- gxemul-0.6.2/test/test_netbsd8.1_hpcmips_install.expect 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/test_netbsd8.1_hpcmips_install.expect 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,66 @@ +#!/usr/local/bin/expect + +set timeout 4000 +spawn ./gxemul -e mobilepro770 -q -d nbsd8.1_hpcmips.img -d b:../../emul/mips/netbsd-hpcmips-8.1/NetBSD-8.1-hpcmips.iso ../../emul/mips/netbsd-hpcmips-8.1/netbsd.gz + +expect " in English" +send "\r" +expect "Install NetBSD to" +send "\r" +expect "b: Yes" +send "b\r" +expect "wd0" +send "\r" +expect "The number of cylinders" +send "\r\r" +expect "Use the entire disk" +send "b\r" +expect "Set sizes of NetBSD partitions" +send "\r" +expect "Accept partition sizes" +send "x\r" +expect "Partition sizes ok" +send "\r" +expect "Please enter a name for" +send "\r" +expect "b: Yes" +send "b\r" +expect "Hit enter to continue" +send "\r" +expect "a: Full installation" +send "\r" +expect "a: CD-ROM" +send "\r" +expect "cd0a" +send "a\r" +expect "device" +send "cd0d\r" +expect "x: Continue" +send "x\r" +expect "Hit enter to continue" +send "\r" +expect "Finished configuring" +send "\r" +expect "Hit enter to continue" +send "\r" +expect "Exit Install System" +send "x\r" +expect "#" +send "mount /dev/wd0a /mnt\r" +expect "#" +send "echo 'console \"/usr/libexec/getty std.9600\" vt100 on secure' >> /mnt/etc/ttys\r" +expect "#" +send "sync\r" +expect "#" +send "sleep 2\r" +expect "#" +send "umount /mnt\r" +expect "#" +send "sync\r" +expect "#" +send "sleep 2\r" +expect "#" +send "halt -p\r" + +close + diff -Nru gxemul-0.6.2/test/test_netbsd8.1_hpcmips_install.sh gxemul-0.7.0+dfsg/test/test_netbsd8.1_hpcmips_install.sh --- gxemul-0.6.2/test/test_netbsd8.1_hpcmips_install.sh 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/test_netbsd8.1_hpcmips_install.sh 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Regression test: +# +# Automated full install of NetBSD/hpcmips, using serial console. +# +# +# 1. Place the iso here: +# +# ../../emul/mips/netbsd-hpcmips-8.1/NetBSD-8.1-hpcmips.iso +# +# 2. Start the regression test with: +# +# test/test_netbsd8.1_hpcmips_install.sh +# + +rm -f nbsd8.1_hpcmips.img +dd if=/dev/zero of=nbsd8.1_hpcmips.img bs=1024 count=1 seek=5000000 + +time test/test_netbsd8.1_hpcmips_install.expect 2> /tmp/gxemul_result + +echo +echo +echo +cat /tmp/gxemul_result + diff -Nru gxemul-0.6.2/test/test_openbsd_luna88k_bootup.expect gxemul-0.7.0+dfsg/test/test_openbsd_luna88k_bootup.expect --- gxemul-0.6.2/test/test_openbsd_luna88k_bootup.expect 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/test_openbsd_luna88k_bootup.expect 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,14 @@ +#!/usr/local/bin/expect + +set timeout 4000 +spawn ./gxemul -e luna-88k -q -d R:liveimage-luna88k-raw-20201206.img boot + +set send_slow {1 .5} + +expect " starting in" +send -s "\r" + +expect "login:" + +close + diff -Nru gxemul-0.6.2/test/test_openbsd_luna88k_bootup.sh gxemul-0.7.0+dfsg/test/test_openbsd_luna88k_bootup.sh --- gxemul-0.6.2/test/test_openbsd_luna88k_bootup.sh 1970-01-01 00:00:00.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/test_openbsd_luna88k_bootup.sh 2021-11-27 09:42:23.000000000 +0000 @@ -0,0 +1,30 @@ +#!/bin/sh +# +# A small test to measure how long time it takes (real time) to boot +# OpenBSD/luna88k up to the login prompt. +# +# Start with: +# +# test/test_openbsd_luna88k_bootup.sh +# +# after making sure that you have 'liveimage-luna88k-raw-20201206.img' and +# 'boot' in the current directory. +# +# +# 2021-04-22 baseline: +# 71.10 seconds: ./configure gcc8 --debug +# 36.70 seconds: ./configure (clang 10.0.1) +# +# M88K_MAX_VPH_TLB_ENTRIES: +# 32 37.21 seconds +# 64 36.76 seconds +# 128 36.70 seconds +# 192 36.67 seconds + + +time test/test_openbsd_luna88k_bootup.expect 2> /tmp/gxemul_result + +echo "-------------------------------------------------" +echo +cat /tmp/gxemul_result + diff -Nru gxemul-0.6.2/test/test_openbsd_mvme88k_install.expect gxemul-0.7.0+dfsg/test/test_openbsd_mvme88k_install.expect --- gxemul-0.6.2/test/test_openbsd_mvme88k_install.expect 2019-06-22 18:23:30.000000000 +0000 +++ gxemul-0.7.0+dfsg/test/test_openbsd_mvme88k_install.expect 2021-11-27 09:42:23.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/local/bin/expect set timeout 4000 -spawn ./gxemul -e mvme187old -q -d obsd_mvme88k.img -d b:../../emul/m88k/openbsd_mvme88k_4.5.iso -j 4.5/mvme88k/bsd.rd +spawn ./gxemul -e mvme187 -q -d obsd_mvme88k.img -d b:../../emul/m88k/openbsd_mvme88k_4.5.iso -j 4.5/mvme88k/bsd.rd set send_slow {1 .5}