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

642 lines
23 KiB

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