《操作系统》的实验代码。
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.

584 lines
20 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 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>] [-prog <prog>] [-Ddef...] [-check <check>] checkargs ...
  214. tag=
  215. prog=
  216. check=check_regexps
  217. while true; do
  218. select=
  219. case $1 in
  220. -tag|-prog)
  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. if [ -z "$prog" ]; then
  242. $make $makeopts touch > /dev/null 2>&1
  243. args="$defs"
  244. else
  245. if [ -z "$tag" ]; then
  246. tag="$prog"
  247. fi
  248. args="build-$prog $defs"
  249. fi
  250. build_run "$tag" "$args"
  251. check_result 'check result' "$check" "$@"
  252. }
  253. quick_run() {
  254. # usage: quick_run <tag> [-Ddef...]
  255. tag="$1"
  256. shift
  257. defs=
  258. while expr "x$1" : "x-D.*" > /dev/null; do
  259. defs="DEFS+='$1' $defs"
  260. shift
  261. done
  262. $make $makeopts touch > /dev/null 2>&1
  263. build_run "$tag" "$defs"
  264. }
  265. quick_check() {
  266. # usage: quick_check <tag> checkargs ...
  267. tag="$1"
  268. shift
  269. check_result "$tag" check_regexps "$@"
  270. }
  271. ## kernel image
  272. osimg=$(make_print ucoreimg)
  273. ## swap image
  274. swapimg=$(make_print swapimg)
  275. ## set default qemu-options
  276. qemuopts="-hda $osimg -drive file=$swapimg,media=disk,cache=writeback"
  277. ## set break-function, default is readline
  278. brkfun=readline
  279. default_check() {
  280. pts=7
  281. check_regexps "$@"
  282. pts=3
  283. quick_check 'check output' \
  284. 'memory management: default_pmm_manager' \
  285. 'check_alloc_page() succeeded!' \
  286. 'check_pgdir() succeeded!' \
  287. 'check_boot_pgdir() succeeded!' \
  288. 'PDE(0e0) c0000000-f8000000 38000000 urw' \
  289. ' |-- PTE(38000) c0000000-f8000000 38000000 -rw' \
  290. 'PDE(001) fac00000-fb000000 00400000 -rw' \
  291. ' |-- PTE(000e0) faf00000-fafe0000 000e0000 urw' \
  292. ' |-- PTE(00001) fafeb000-fafec000 00001000 -rw' \
  293. 'check_vma_struct() succeeded!' \
  294. 'page fault at 0x00000100: K/W [no page found].' \
  295. 'check_pgfault() succeeded!' \
  296. 'check_vmm() succeeded.' \
  297. 'page fault at 0x00001000: K/W [no page found].' \
  298. 'page fault at 0x00002000: K/W [no page found].' \
  299. 'page fault at 0x00003000: K/W [no page found].' \
  300. 'page fault at 0x00004000: K/W [no page found].' \
  301. 'write Virt Page e in fifo_check_swap' \
  302. 'page fault at 0x00005000: K/W [no page found].' \
  303. 'page fault at 0x00001000: K/W [no page found]' \
  304. 'page fault at 0x00002000: K/W [no page found].' \
  305. 'page fault at 0x00003000: K/W [no page found].' \
  306. 'page fault at 0x00004000: K/W [no page found].' \
  307. 'check_swap() succeeded!' \
  308. '++ setup timer interrupts'
  309. }
  310. ## check now!!
  311. run_test -prog 'badsegment' -check default_check \
  312. 'kernel_execve: pid = 2, name = "badsegment".' \
  313. - 'trapframe at 0xc.......' \
  314. 'trap 0x0000000d General Protection' \
  315. ' err 0x00000028' \
  316. - ' eip 0x008.....' \
  317. - ' esp 0xaff.....' \
  318. ' cs 0x----001b' \
  319. ' ss 0x----0023' \
  320. ! - 'user panic at .*'
  321. run_test -prog 'divzero' -check default_check \
  322. 'kernel_execve: pid = 2, name = "divzero".' \
  323. - 'trapframe at 0xc.......' \
  324. 'trap 0x00000000 Divide error' \
  325. - ' eip 0x008.....' \
  326. - ' esp 0xaff.....' \
  327. ' cs 0x----001b' \
  328. ' ss 0x----0023' \
  329. ! - 'user panic at .*'
  330. run_test -prog 'softint' -check default_check \
  331. 'kernel_execve: pid = 2, name = "softint".' \
  332. - 'trapframe at 0xc.......' \
  333. 'trap 0x0000000d General Protection' \
  334. ' err 0x00000072' \
  335. - ' eip 0x008.....' \
  336. - ' esp 0xaff.....' \
  337. ' cs 0x----001b' \
  338. ' ss 0x----0023' \
  339. ! - 'user panic at .*'
  340. pts=10
  341. run_test -prog 'faultread' -check default_check \
  342. 'kernel_execve: pid = 2, name = "faultread".' \
  343. - 'trapframe at 0xc.......' \
  344. 'trap 0x0000000e Page Fault' \
  345. ' err 0x00000004' \
  346. - ' eip 0x008.....' \
  347. ! - 'user panic at .*'
  348. run_test -prog 'faultreadkernel' -check default_check \
  349. 'kernel_execve: pid = 2, name = "faultreadkernel".' \
  350. - 'trapframe at 0xc.......' \
  351. 'trap 0x0000000e Page Fault' \
  352. ' err 0x00000005' \
  353. - ' eip 0x008.....' \
  354. ! - 'user panic at .*'
  355. run_test -prog 'hello' -check default_check \
  356. 'kernel_execve: pid = 2, name = "hello".' \
  357. 'Hello world!!.' \
  358. 'I am process 2.' \
  359. 'hello pass.'
  360. run_test -prog 'testbss' -check default_check \
  361. 'kernel_execve: pid = 2, name = "testbss".' \
  362. 'Making sure bss works right...' \
  363. 'Yes, good. Now doing a wild write off the end...' \
  364. 'testbss may pass.' \
  365. - 'trapframe at 0xc.......' \
  366. 'trap 0x0000000e Page Fault' \
  367. ' err 0x00000006' \
  368. - ' eip 0x008.....' \
  369. 'killed by kernel.' \
  370. ! - 'user panic at .*'
  371. run_test -prog 'pgdir' -check default_check \
  372. 'kernel_execve: pid = 2, name = "pgdir".' \
  373. 'I am 2, print pgdir.' \
  374. 'PDE(001) 00800000-00c00000 00400000 urw' \
  375. ' |-- PTE(00002) 00800000-00802000 00002000 ur-' \
  376. ' |-- PTE(00001) 00802000-00803000 00001000 urw' \
  377. 'PDE(001) afc00000-b0000000 00400000 urw' \
  378. ' |-- PTE(00004) afffc000-b0000000 00004000 urw' \
  379. 'PDE(0e0) c0000000-f8000000 38000000 urw' \
  380. ' |-- PTE(38000) c0000000-f8000000 38000000 -rw' \
  381. 'pgdir pass.'
  382. run_test -prog 'yield' -check default_check \
  383. 'kernel_execve: pid = 2, name = "yield".' \
  384. 'Hello, I am process 2.' \
  385. 'Back in process 2, iteration 0.' \
  386. 'Back in process 2, iteration 1.' \
  387. 'Back in process 2, iteration 2.' \
  388. 'Back in process 2, iteration 3.' \
  389. 'Back in process 2, iteration 4.' \
  390. 'All done in process 2.' \
  391. 'yield pass.'
  392. run_test -prog 'badarg' -check default_check \
  393. 'kernel_execve: pid = 2, name = "badarg".' \
  394. 'fork ok.' \
  395. 'badarg pass.' \
  396. 'all user-mode processes have quit.' \
  397. 'init check memory pass.' \
  398. ! - 'user panic at .*'
  399. pts=10
  400. run_test -prog 'exit' -check default_check \
  401. 'kernel_execve: pid = 2, name = "exit".' \
  402. 'I am the parent. Forking the child...' \
  403. 'I am the parent, waiting now..' \
  404. 'I am the child.' \
  405. - 'waitpid [0-9]+ ok\.' \
  406. 'exit pass.' \
  407. 'all user-mode processes have quit.' \
  408. 'init check memory pass.' \
  409. ! - 'user panic at .*'
  410. run_test -prog 'spin' -check default_check \
  411. 'kernel_execve: pid = 2, name = "spin".' \
  412. 'I am the parent. Forking the child...' \
  413. 'I am the parent. Running the child...' \
  414. 'I am the child. spinning ...' \
  415. 'I am the parent. Killing the child...' \
  416. 'kill returns 0' \
  417. 'wait returns 0' \
  418. 'spin may pass.' \
  419. 'all user-mode processes have quit.' \
  420. 'init check memory pass.' \
  421. ! - 'user panic at .*'
  422. run_test -prog 'waitkill' -check default_check \
  423. 'kernel_execve: pid = 2, name = "waitkill".' \
  424. 'wait child 1.' \
  425. 'child 2.' \
  426. 'child 1.' \
  427. 'kill parent ok.' \
  428. 'kill child1 ok.' \
  429. 'all user-mode processes have quit.' \
  430. 'init check memory pass.' \
  431. ! - 'user panic at .*'
  432. pts=15
  433. run_test -prog 'forktest' -check default_check \
  434. 'kernel_execve: pid = 2, name = "forktest".' \
  435. 'I am child 31' \
  436. 'I am child 19' \
  437. 'I am child 13' \
  438. 'I am child 0' \
  439. 'forktest pass.' \
  440. 'all user-mode processes have quit.' \
  441. 'init check memory pass.' \
  442. ! - 'fork claimed to work [0-9]+ times!' \
  443. ! 'wait stopped early' \
  444. ! 'wait got too many' \
  445. ! - 'user panic at .*'
  446. pts=10
  447. run_test -prog 'forktree' -check default_check \
  448. 'kernel_execve: pid = 2, name = "forktree".' \
  449. - '....: I am '\'''\' \
  450. - '....: I am '\''0'\' \
  451. - '....: I am '\'''\' \
  452. - '....: I am '\''1'\' \
  453. - '....: I am '\''0'\' \
  454. - '....: I am '\''01'\' \
  455. - '....: I am '\''00'\' \
  456. - '....: I am '\''11'\' \
  457. - '....: I am '\''10'\' \
  458. - '....: I am '\''101'\' \
  459. - '....: I am '\''100'\' \
  460. - '....: I am '\''111'\' \
  461. - '....: I am '\''110'\' \
  462. - '....: I am '\''001'\' \
  463. - '....: I am '\''000'\' \
  464. - '....: I am '\''011'\' \
  465. - '....: I am '\''010'\' \
  466. - '....: I am '\''0101'\' \
  467. - '....: I am '\''0100'\' \
  468. - '....: I am '\''0111'\' \
  469. - '....: I am '\''0110'\' \
  470. - '....: I am '\''0001'\' \
  471. - '....: I am '\''0000'\' \
  472. - '....: I am '\''0011'\' \
  473. - '....: I am '\''0010'\' \
  474. - '....: I am '\''1101'\' \
  475. - '....: I am '\''1100'\' \
  476. - '....: I am '\''1111'\' \
  477. - '....: I am '\''1110'\' \
  478. - '....: I am '\''1001'\' \
  479. - '....: I am '\''1000'\' \
  480. - '....: I am '\''1011'\' \
  481. - '....: I am '\''1010'\' \
  482. 'all user-mode processes have quit.' \
  483. 'init check memory pass.'
  484. pts=20
  485. timeout=500
  486. run_test -prog 'matrix' -check default_check \
  487. 'kernel_execve: pid = 2, name = "matrix".' \
  488. 'fork ok.' \
  489. 'pid 4 done!.' \
  490. 'pid 7 done!.' \
  491. 'pid 13 done!.' \
  492. 'pid 17 done!.' \
  493. 'pid 23 done!.' \
  494. 'matrix pass.' \
  495. 'all user-mode processes have quit.' \
  496. 'init check memory pass.' \
  497. ! - 'user panic at .*'
  498. pts=20
  499. timeout=150
  500. run_test -prog 'priority' -check default_check \
  501. 'sched class: stride_scheduler' \
  502. 'kernel_execve: pid = 2, name = "priority".' \
  503. 'main: fork ok,now need to wait pids.' \
  504. 'stride sched correct result: 1 2 3 4 5' \
  505. 'all user-mode processes have quit.' \
  506. 'init check memory pass.' \
  507. ! - 'user panic at .*'
  508. ## print final-score
  509. show_final