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

640 lines
23 KiB

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