《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
5.9 KiB

12 years ago
12 years ago
12 years ago
12 years ago
  1. #!/bin/sh
  2. verbose=false
  3. if [ "x$1" = "x-v" ]; then
  4. verbose=true
  5. out=/dev/stdout
  6. err=/dev/stderr
  7. else
  8. out=/dev/null
  9. err=/dev/null
  10. fi
  11. ## make & makeopts
  12. if gmake --version > /dev/null 2>&1; then
  13. make=gmake;
  14. else
  15. make=make;
  16. fi
  17. makeopts="--quiet --no-print-directory -j"
  18. make_print() {
  19. echo `$make $makeopts print-$1`
  20. }
  21. ## command tools
  22. awk='awk'
  23. bc='bc'
  24. date='date'
  25. grep='grep'
  26. rm='rm -f'
  27. sed='sed'
  28. ## symbol table
  29. sym_table='obj/kernel.sym'
  30. ## gdb & gdbopts
  31. gdb="$(make_print GCCPREFIX)gdb"
  32. gdbport='1234'
  33. gdb_in="$(make_print GRADE_GDB_IN)"
  34. ## qemu & qemuopts
  35. qemu="$(make_print qemu)"
  36. qemu_out="$(make_print GRADE_QEMU_OUT)"
  37. if $qemu -nographic -help | grep -q '^-gdb'; then
  38. qemugdb="-gdb tcp::$gdbport"
  39. else
  40. qemugdb="-s -p $gdbport"
  41. fi
  42. ## default variables
  43. default_timeout=30
  44. default_pts=5
  45. pts=5
  46. part=0
  47. part_pos=0
  48. total=0
  49. total_pos=0
  50. ## default functions
  51. update_score() {
  52. total=`expr $total + $part`
  53. total_pos=`expr $total_pos + $part_pos`
  54. part=0
  55. part_pos=0
  56. }
  57. get_time() {
  58. echo `$date +%s.%N 2> /dev/null`
  59. }
  60. show_part() {
  61. echo "Part $1 Score: $part/$part_pos"
  62. echo
  63. update_score
  64. }
  65. show_final() {
  66. update_score
  67. echo "Total Score: $total/$total_pos"
  68. if [ $total -lt $total_pos ]; then
  69. exit 1
  70. fi
  71. }
  72. show_time() {
  73. t1=$(get_time)
  74. time=`echo "scale=1; ($t1-$t0)/1" | $sed 's/.N/.0/g' | $bc 2> /dev/null`
  75. echo "(${time}s)"
  76. }
  77. show_build_tag() {
  78. echo "$1:" | $awk '{printf "%-24s ", $0}'
  79. }
  80. show_check_tag() {
  81. echo "$1:" | $awk '{printf " -%-40s ", $0}'
  82. }
  83. show_msg() {
  84. echo $1
  85. shift
  86. if [ $# -gt 0 ]; then
  87. echo -e "$@" | awk '{printf " %s\n", $0}'
  88. echo
  89. fi
  90. }
  91. pass() {
  92. show_msg OK "$@"
  93. part=`expr $part + $pts`
  94. part_pos=`expr $part_pos + $pts`
  95. }
  96. fail() {
  97. show_msg WRONG "$@"
  98. part_pos=`expr $part_pos + $pts`
  99. }
  100. run_qemu() {
  101. # Run qemu with serial output redirected to $qemu_out. If $brkfun is non-empty,
  102. # wait until $brkfun is reached or $timeout expires, then kill QEMU
  103. qemuextra=
  104. if [ "$brkfun" ]; then
  105. qemuextra="-S $qemugdb"
  106. fi
  107. if [ -z "$timeout" ] || [ $timeout -le 0 ]; then
  108. timeout=$default_timeout;
  109. fi
  110. t0=$(get_time)
  111. (
  112. ulimit -t $timeout
  113. exec $qemu -nographic $qemuopts -serial file:$qemu_out -monitor null -no-reboot $qemuextra
  114. ) > $out 2> $err &
  115. pid=$!
  116. # wait for QEMU to start
  117. sleep 1
  118. if [ -n "$brkfun" ]; then
  119. # find the address of the kernel $brkfun function
  120. brkaddr=`$grep " $brkfun\$" $sym_table | $sed -e's/ .*$//g'`
  121. brkaddr_phys=`echo $brkaddr | sed "s/^c0/00/g"`
  122. (
  123. echo "target remote localhost:$gdbport"
  124. echo "break *0x$brkaddr"
  125. if [ "$brkaddr" != "$brkaddr_phys" ]; then
  126. echo "break *0x$brkaddr_phys"
  127. fi
  128. echo "continue"
  129. ) > $gdb_in
  130. $gdb -batch -nx -x $gdb_in > /dev/null 2>&1
  131. # make sure that QEMU is dead
  132. # on OS X, exiting gdb doesn't always exit qemu
  133. kill $pid > /dev/null 2>&1
  134. fi
  135. }
  136. build_run() {
  137. # usage: build_run <tag> <args>
  138. show_build_tag "$1"
  139. shift
  140. if $verbose; then
  141. echo "$make $@ ..."
  142. fi
  143. $make $makeopts $@ 'DEFS+=-DDEBUG_GRADE' > $out 2> $err
  144. if [ $? -ne 0 ]; then
  145. echo $make $@ failed
  146. exit 1
  147. fi
  148. # now run qemu and save the output
  149. run_qemu
  150. show_time
  151. }
  152. check_result() {
  153. # usage: check_result <tag> <check> <check args...>
  154. show_check_tag "$1"
  155. shift
  156. # give qemu some time to run (for asynchronous mode)
  157. if [ ! -s $qemu_out ]; then
  158. sleep 4
  159. fi
  160. if [ ! -s $qemu_out ]; then
  161. fail > /dev/null
  162. echo 'no $qemu_out'
  163. else
  164. check=$1
  165. shift
  166. $check "$@"
  167. fi
  168. }
  169. check_regexps() {
  170. okay=yes
  171. not=0
  172. reg=0
  173. error=
  174. for i do
  175. if [ "x$i" = "x!" ]; then
  176. not=1
  177. elif [ "x$i" = "x-" ]; then
  178. reg=1
  179. else
  180. if [ $reg -ne 0 ]; then
  181. $grep '-E' "^$i\$" $qemu_out > /dev/null
  182. else
  183. $grep '-F' "$i" $qemu_out > /dev/null
  184. fi
  185. found=$(($? == 0))
  186. if [ $found -eq $not ]; then
  187. if [ $found -eq 0 ]; then
  188. msg="!! error: missing '$i'"
  189. else
  190. msg="!! error: got unexpected line '$i'"
  191. fi
  192. okay=no
  193. if [ -z "$error" ]; then
  194. error="$msg"
  195. else
  196. error="$error\n$msg"
  197. fi
  198. fi
  199. not=0
  200. reg=0
  201. fi
  202. done
  203. if [ "$okay" = "yes" ]; then
  204. pass
  205. else
  206. fail "$error"
  207. if $verbose; then
  208. exit 1
  209. fi
  210. fi
  211. }
  212. run_test() {
  213. # usage: run_test [-tag <tag>] [-Ddef...] [-check <check>] checkargs ...
  214. tag=
  215. check=check_regexps
  216. while true; do
  217. select=
  218. case $1 in
  219. -tag)
  220. select=`expr substr $1 2 ${#1}`
  221. eval $select='$2'
  222. ;;
  223. esac
  224. if [ -z "$select" ]; then
  225. break
  226. fi
  227. shift
  228. shift
  229. done
  230. defs=
  231. while expr "x$1" : "x-D.*" > /dev/null; do
  232. defs="DEFS+='$1' $defs"
  233. shift
  234. done
  235. if [ "x$1" = "x-check" ]; then
  236. check=$2
  237. shift
  238. shift
  239. fi
  240. $make $makeopts touch > /dev/null 2>&1
  241. build_run "$tag" "$defs"
  242. check_result 'check result' "$check" "$@"
  243. }
  244. quick_run() {
  245. # usage: quick_run <tag> [-Ddef...]
  246. tag="$1"
  247. shift
  248. defs=
  249. while expr "x$1" : "x-D.*" > /dev/null; do
  250. defs="DEFS+='$1' $defs"
  251. shift
  252. done
  253. $make $makeopts touch > /dev/null 2>&1
  254. build_run "$tag" "$defs"
  255. }
  256. quick_check() {
  257. # usage: quick_check <tag> checkargs ...
  258. tag="$1"
  259. shift
  260. check_result "$tag" check_regexps "$@"
  261. }
  262. ## kernel image
  263. osimg=$(make_print ucoreimg)
  264. ## set default qemu-options
  265. qemuopts="-hda $osimg"
  266. ## set break-function, default is readline
  267. brkfun=readline
  268. ## check now!!
  269. quick_run 'Check Output'
  270. pts=10
  271. quick_check 'check ring 0' \
  272. '0: @ring 0' \
  273. '0: cs = 8' \
  274. '0: ds = 10' \
  275. '0: es = 10' \
  276. '0: ss = 10'
  277. quick_check 'check switch to ring 3' \
  278. '+++ switch to user mode +++' \
  279. '1: @ring 3' \
  280. '1: cs = 1b' \
  281. '1: ds = 23' \
  282. '1: es = 23' \
  283. '1: ss = 23'
  284. quick_check 'check switch to ring 0' \
  285. '+++ switch to kernel mode +++' \
  286. '2: @ring 0' \
  287. '2: cs = 8' \
  288. '2: ds = 10' \
  289. '2: es = 10' \
  290. '2: ss = 10'
  291. quick_check 'check ticks' \
  292. '++ setup timer interrupts' \
  293. '100 ticks' \
  294. 'End of Test.'
  295. ## print final-score
  296. show_final