《操作系统》的实验代码。
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

353 行
5.9 KiB

  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. cp $qemu_out .`echo $tag | tr '[:upper:]' '[:lower:]' | sed 's/ /_/g'`.log
  152. }
  153. check_result() {
  154. # usage: check_result <tag> <check> <check args...>
  155. show_check_tag "$1"
  156. shift
  157. # give qemu some time to run (for asynchronous mode)
  158. if [ ! -s $qemu_out ]; then
  159. sleep 4
  160. fi
  161. if [ ! -s $qemu_out ]; then
  162. fail > /dev/null
  163. echo 'no $qemu_out'
  164. else
  165. check=$1
  166. shift
  167. $check "$@"
  168. fi
  169. }
  170. check_regexps() {
  171. okay=yes
  172. not=0
  173. reg=0
  174. error=
  175. for i do
  176. if [ "x$i" = "x!" ]; then
  177. not=1
  178. elif [ "x$i" = "x-" ]; then
  179. reg=1
  180. else
  181. if [ $reg -ne 0 ]; then
  182. $grep '-E' "^$i\$" $qemu_out > /dev/null
  183. else
  184. $grep '-F' "$i" $qemu_out > /dev/null
  185. fi
  186. found=$(($? == 0))
  187. if [ $found -eq $not ]; then
  188. if [ $found -eq 0 ]; then
  189. msg="!! error: missing '$i'"
  190. else
  191. msg="!! error: got unexpected line '$i'"
  192. fi
  193. okay=no
  194. if [ -z "$error" ]; then
  195. error="$msg"
  196. else
  197. error="$error\n$msg"
  198. fi
  199. fi
  200. not=0
  201. reg=0
  202. fi
  203. done
  204. if [ "$okay" = "yes" ]; then
  205. pass
  206. else
  207. fail "$error"
  208. if $verbose; then
  209. exit 1
  210. fi
  211. fi
  212. }
  213. run_test() {
  214. # usage: run_test [-tag <tag>] [-Ddef...] [-check <check>] checkargs ...
  215. tag=
  216. check=check_regexps
  217. while true; do
  218. select=
  219. case $1 in
  220. -tag)
  221. select=`expr substr $1 2 ${#1}`
  222. eval $select='$2'
  223. ;;
  224. esac
  225. if [ -z "$select" ]; then
  226. break
  227. fi
  228. shift
  229. shift
  230. done
  231. defs=
  232. while expr "x$1" : "x-D.*" > /dev/null; do
  233. defs="DEFS+='$1' $defs"
  234. shift
  235. done
  236. if [ "x$1" = "x-check" ]; then
  237. check=$2
  238. shift
  239. shift
  240. fi
  241. $make $makeopts touch > /dev/null 2>&1
  242. build_run "$tag" "$defs"
  243. check_result 'check result' "$check" "$@"
  244. }
  245. quick_run() {
  246. # usage: quick_run <tag> [-Ddef...]
  247. tag="$1"
  248. shift
  249. defs=
  250. while expr "x$1" : "x-D.*" > /dev/null; do
  251. defs="DEFS+='$1' $defs"
  252. shift
  253. done
  254. $make $makeopts touch > /dev/null 2>&1
  255. build_run "$tag" "$defs"
  256. }
  257. quick_check() {
  258. # usage: quick_check <tag> checkargs ...
  259. tag="$1"
  260. shift
  261. check_result "$tag" check_regexps "$@"
  262. }
  263. ## kernel image
  264. osimg=$(make_print ucoreimg)
  265. ## set default qemu-options
  266. qemuopts="-hda $osimg"
  267. ## set break-function, default is readline
  268. brkfun=readline
  269. ## check now!!
  270. quick_run 'Check Output'
  271. pts=10
  272. quick_check 'check ring 0' \
  273. '0: @ring 0' \
  274. '0: cs = 8' \
  275. '0: ds = 10' \
  276. '0: es = 10' \
  277. '0: ss = 10'
  278. quick_check 'check switch to ring 3' \
  279. '+++ switch to user mode +++' \
  280. '1: @ring 3' \
  281. '1: cs = 1b' \
  282. '1: ds = 23' \
  283. '1: es = 23' \
  284. '1: ss = 23'
  285. quick_check 'check switch to ring 0' \
  286. '+++ switch to kernel mode +++' \
  287. '2: @ring 0' \
  288. '2: cs = 8' \
  289. '2: ds = 10' \
  290. '2: es = 10' \
  291. '2: ss = 10'
  292. quick_check 'check ticks' \
  293. '++ setup timer interrupts' \
  294. '100 ticks' \
  295. 'End of Test.'
  296. ## print final-score
  297. show_final