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

581 lines
20 KiB

преди 12 години
  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 "$@" | 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. (
  122. echo "target remote localhost:$gdbport"
  123. echo "break *0x$brkaddr"
  124. echo "continue"
  125. ) > $gdb_in
  126. $gdb -batch -nx -x $gdb_in > /dev/null 2>&1
  127. # make sure that QEMU is dead
  128. # on OS X, exiting gdb doesn't always exit qemu
  129. kill $pid > /dev/null 2>&1
  130. fi
  131. }
  132. build_run() {
  133. # usage: build_run <tag> <args>
  134. show_build_tag "$1"
  135. shift
  136. if $verbose; then
  137. echo "$make $@ ..."
  138. fi
  139. $make $makeopts $@ 'DEFS+=-DDEBUG_GRADE' > $out 2> $err
  140. if [ $? -ne 0 ]; then
  141. echo $make $@ failed
  142. exit 1
  143. fi
  144. # now run qemu and save the output
  145. run_qemu
  146. show_time
  147. }
  148. check_result() {
  149. # usage: check_result <tag> <check> <check args...>
  150. show_check_tag "$1"
  151. shift
  152. # give qemu some time to run (for asynchronous mode)
  153. if [ ! -s $qemu_out ]; then
  154. sleep 4
  155. fi
  156. if [ ! -s $qemu_out ]; then
  157. fail > /dev/null
  158. echo 'no $qemu_out'
  159. else
  160. check=$1
  161. shift
  162. $check "$@"
  163. fi
  164. }
  165. check_regexps() {
  166. okay=yes
  167. not=0
  168. reg=0
  169. error=
  170. for i do
  171. if [ "x$i" = "x!" ]; then
  172. not=1
  173. elif [ "x$i" = "x-" ]; then
  174. reg=1
  175. else
  176. if [ $reg -ne 0 ]; then
  177. $grep '-E' "^$i\$" $qemu_out > /dev/null
  178. else
  179. $grep '-F' "$i" $qemu_out > /dev/null
  180. fi
  181. found=$(($? == 0))
  182. if [ $found -eq $not ]; then
  183. if [ $found -eq 0 ]; then
  184. msg="!! error: missing '$i'"
  185. else
  186. msg="!! error: got unexpected line '$i'"
  187. fi
  188. okay=no
  189. if [ -z "$error" ]; then
  190. error="$msg"
  191. else
  192. error="$error\n$msg"
  193. fi
  194. fi
  195. not=0
  196. reg=0
  197. fi
  198. done
  199. if [ "$okay" = "yes" ]; then
  200. pass
  201. else
  202. fail "$error"
  203. if $verbose; then
  204. exit 1
  205. fi
  206. fi
  207. }
  208. run_test() {
  209. # usage: run_test [-tag <tag>] [-prog <prog>] [-Ddef...] [-check <check>] checkargs ...
  210. tag=
  211. prog=
  212. check=check_regexps
  213. while true; do
  214. select=
  215. case $1 in
  216. -tag|-prog)
  217. select=`expr substr $1 2 ${#1}`
  218. eval $select='$2'
  219. ;;
  220. esac
  221. if [ -z "$select" ]; then
  222. break
  223. fi
  224. shift
  225. shift
  226. done
  227. defs=
  228. while expr "x$1" : "x-D.*" > /dev/null; do
  229. defs="DEFS+='$1' $defs"
  230. shift
  231. done
  232. if [ "x$1" = "x-check" ]; then
  233. check=$2
  234. shift
  235. shift
  236. fi
  237. if [ -z "$prog" ]; then
  238. $make $makeopts touch > /dev/null 2>&1
  239. args="$defs"
  240. else
  241. if [ -z "$tag" ]; then
  242. tag="$prog"
  243. fi
  244. args="build-$prog $defs"
  245. fi
  246. build_run "$tag" "$args"
  247. check_result 'check result' "$check" "$@"
  248. }
  249. quick_run() {
  250. # usage: quick_run <tag> [-Ddef...]
  251. tag="$1"
  252. shift
  253. defs=
  254. while expr "x$1" : "x-D.*" > /dev/null; do
  255. defs="DEFS+='$1' $defs"
  256. shift
  257. done
  258. $make $makeopts touch > /dev/null 2>&1
  259. build_run "$tag" "$defs"
  260. }
  261. quick_check() {
  262. # usage: quick_check <tag> checkargs ...
  263. tag="$1"
  264. shift
  265. check_result "$tag" check_regexps "$@"
  266. }
  267. ## kernel image
  268. osimg=$(make_print ucoreimg)
  269. ## swap image
  270. swapimg=$(make_print swapimg)
  271. ## set default qemu-options
  272. qemuopts="-hda $osimg -drive file=$swapimg,media=disk,cache=writeback"
  273. ## set break-function, default is readline
  274. brkfun=readline
  275. default_check() {
  276. pts=7
  277. check_regexps "$@"
  278. pts=3
  279. quick_check 'check output' \
  280. 'memory management: default_pmm_manager' \
  281. 'check_alloc_page() succeeded!' \
  282. 'check_pgdir() succeeded!' \
  283. 'check_boot_pgdir() succeeded!' \
  284. 'PDE(0e0) c0000000-f8000000 38000000 urw' \
  285. ' |-- PTE(38000) c0000000-f8000000 38000000 -rw' \
  286. 'PDE(001) fac00000-fb000000 00400000 -rw' \
  287. ' |-- PTE(000e0) faf00000-fafe0000 000e0000 urw' \
  288. ' |-- PTE(00001) fafeb000-fafec000 00001000 -rw' \
  289. 'check_vma_struct() succeeded!' \
  290. 'page fault at 0x00000100: K/W [no page found].' \
  291. 'check_pgfault() succeeded!' \
  292. 'check_vmm() succeeded.' \
  293. 'page fault at 0x00001000: K/W [no page found].' \
  294. 'page fault at 0x00002000: K/W [no page found].' \
  295. 'page fault at 0x00003000: K/W [no page found].' \
  296. 'page fault at 0x00004000: K/W [no page found].' \
  297. 'write Virt Page e in fifo_check_swap' \
  298. 'page fault at 0x00005000: K/W [no page found].' \
  299. 'page fault at 0x00001000: K/W [no page found]' \
  300. 'page fault at 0x00002000: K/W [no page found].' \
  301. 'page fault at 0x00003000: K/W [no page found].' \
  302. 'page fault at 0x00004000: K/W [no page found].' \
  303. 'check_swap() succeeded!' \
  304. '++ setup timer interrupts'
  305. }
  306. ## check now!!
  307. run_test -prog 'badsegment' -check default_check \
  308. 'kernel_execve: pid = 2, name = "badsegment".' \
  309. - 'trapframe at 0xc.......' \
  310. 'trap 0x0000000d General Protection' \
  311. ' err 0x00000028' \
  312. - ' eip 0x008.....' \
  313. - ' esp 0xaff.....' \
  314. ' cs 0x----001b' \
  315. ' ss 0x----0023' \
  316. ! - 'user panic at .*'
  317. run_test -prog 'divzero' -check default_check \
  318. 'kernel_execve: pid = 2, name = "divzero".' \
  319. - 'trapframe at 0xc.......' \
  320. 'trap 0x00000000 Divide error' \
  321. - ' eip 0x008.....' \
  322. - ' esp 0xaff.....' \
  323. ' cs 0x----001b' \
  324. ' ss 0x----0023' \
  325. ! - 'user panic at .*'
  326. run_test -prog 'softint' -check default_check \
  327. 'kernel_execve: pid = 2, name = "softint".' \
  328. - 'trapframe at 0xc.......' \
  329. 'trap 0x0000000d General Protection' \
  330. ' err 0x00000072' \
  331. - ' eip 0x008.....' \
  332. - ' esp 0xaff.....' \
  333. ' cs 0x----001b' \
  334. ' ss 0x----0023' \
  335. ! - 'user panic at .*'
  336. pts=10
  337. run_test -prog 'faultread' -check default_check \
  338. 'kernel_execve: pid = 2, name = "faultread".' \
  339. - 'trapframe at 0xc.......' \
  340. 'trap 0x0000000e Page Fault' \
  341. ' err 0x00000004' \
  342. - ' eip 0x008.....' \
  343. ! - 'user panic at .*'
  344. run_test -prog 'faultreadkernel' -check default_check \
  345. 'kernel_execve: pid = 2, name = "faultreadkernel".' \
  346. - 'trapframe at 0xc.......' \
  347. 'trap 0x0000000e Page Fault' \
  348. ' err 0x00000005' \
  349. - ' eip 0x008.....' \
  350. ! - 'user panic at .*'
  351. run_test -prog 'hello' -check default_check \
  352. 'kernel_execve: pid = 2, name = "hello".' \
  353. 'Hello world!!.' \
  354. 'I am process 2.' \
  355. 'hello pass.'
  356. run_test -prog 'testbss' -check default_check \
  357. 'kernel_execve: pid = 2, name = "testbss".' \
  358. 'Making sure bss works right...' \
  359. 'Yes, good. Now doing a wild write off the end...' \
  360. 'testbss may pass.' \
  361. - 'trapframe at 0xc.......' \
  362. 'trap 0x0000000e Page Fault' \
  363. ' err 0x00000006' \
  364. - ' eip 0x008.....' \
  365. 'killed by kernel.' \
  366. ! - 'user panic at .*'
  367. run_test -prog 'pgdir' -check default_check \
  368. 'kernel_execve: pid = 2, name = "pgdir".' \
  369. 'I am 2, print pgdir.' \
  370. 'PDE(001) 00800000-00c00000 00400000 urw' \
  371. ' |-- PTE(00002) 00800000-00802000 00002000 ur-' \
  372. ' |-- PTE(00001) 00802000-00803000 00001000 urw' \
  373. 'PDE(001) afc00000-b0000000 00400000 urw' \
  374. ' |-- PTE(00004) afffc000-b0000000 00004000 urw' \
  375. 'PDE(0e0) c0000000-f8000000 38000000 urw' \
  376. ' |-- PTE(38000) c0000000-f8000000 38000000 -rw' \
  377. 'pgdir pass.'
  378. run_test -prog 'yield' -check default_check \
  379. 'kernel_execve: pid = 2, name = "yield".' \
  380. 'Hello, I am process 2.' \
  381. 'Back in process 2, iteration 0.' \
  382. 'Back in process 2, iteration 1.' \
  383. 'Back in process 2, iteration 2.' \
  384. 'Back in process 2, iteration 3.' \
  385. 'Back in process 2, iteration 4.' \
  386. 'All done in process 2.' \
  387. 'yield pass.'
  388. run_test -prog 'badarg' -check default_check \
  389. 'kernel_execve: pid = 2, name = "badarg".' \
  390. 'fork ok.' \
  391. 'badarg pass.' \
  392. 'all user-mode processes have quit.' \
  393. 'init check memory pass.' \
  394. ! - 'user panic at .*'
  395. pts=10
  396. run_test -prog 'exit' -check default_check \
  397. 'kernel_execve: pid = 2, name = "exit".' \
  398. 'I am the parent. Forking the child...' \
  399. 'I am the parent, waiting now..' \
  400. 'I am the child.' \
  401. - 'waitpid [0-9]+ ok\.' \
  402. 'exit pass.' \
  403. 'all user-mode processes have quit.' \
  404. 'init check memory pass.' \
  405. ! - 'user panic at .*'
  406. run_test -prog 'spin' -check default_check \
  407. 'kernel_execve: pid = 2, name = "spin".' \
  408. 'I am the parent. Forking the child...' \
  409. 'I am the parent. Running the child...' \
  410. 'I am the child. spinning ...' \
  411. 'I am the parent. Killing the child...' \
  412. 'kill returns 0' \
  413. 'wait returns 0' \
  414. 'spin may pass.' \
  415. 'all user-mode processes have quit.' \
  416. 'init check memory pass.' \
  417. ! - 'user panic at .*'
  418. run_test -prog 'waitkill' -check default_check \
  419. 'kernel_execve: pid = 2, name = "waitkill".' \
  420. 'wait child 1.' \
  421. 'child 2.' \
  422. 'child 1.' \
  423. 'kill parent ok.' \
  424. 'kill child1 ok.' \
  425. 'all user-mode processes have quit.' \
  426. 'init check memory pass.' \
  427. ! - 'user panic at .*'
  428. pts=15
  429. run_test -prog 'forktest' -check default_check \
  430. 'kernel_execve: pid = 2, name = "forktest".' \
  431. 'I am child 31' \
  432. 'I am child 19' \
  433. 'I am child 13' \
  434. 'I am child 0' \
  435. 'forktest pass.' \
  436. 'all user-mode processes have quit.' \
  437. 'init check memory pass.' \
  438. ! - 'fork claimed to work [0-9]+ times!' \
  439. ! 'wait stopped early' \
  440. ! 'wait got too many' \
  441. ! - 'user panic at .*'
  442. pts=10
  443. run_test -prog 'forktree' -check default_check \
  444. 'kernel_execve: pid = 2, name = "forktree".' \
  445. - '....: I am '\'''\' \
  446. - '....: I am '\''0'\' \
  447. - '....: I am '\'''\' \
  448. - '....: I am '\''1'\' \
  449. - '....: I am '\''0'\' \
  450. - '....: I am '\''01'\' \
  451. - '....: I am '\''00'\' \
  452. - '....: I am '\''11'\' \
  453. - '....: I am '\''10'\' \
  454. - '....: I am '\''101'\' \
  455. - '....: I am '\''100'\' \
  456. - '....: I am '\''111'\' \
  457. - '....: I am '\''110'\' \
  458. - '....: I am '\''001'\' \
  459. - '....: I am '\''000'\' \
  460. - '....: I am '\''011'\' \
  461. - '....: I am '\''010'\' \
  462. - '....: I am '\''0101'\' \
  463. - '....: I am '\''0100'\' \
  464. - '....: I am '\''0111'\' \
  465. - '....: I am '\''0110'\' \
  466. - '....: I am '\''0001'\' \
  467. - '....: I am '\''0000'\' \
  468. - '....: I am '\''0011'\' \
  469. - '....: I am '\''0010'\' \
  470. - '....: I am '\''1101'\' \
  471. - '....: I am '\''1100'\' \
  472. - '....: I am '\''1111'\' \
  473. - '....: I am '\''1110'\' \
  474. - '....: I am '\''1001'\' \
  475. - '....: I am '\''1000'\' \
  476. - '....: I am '\''1011'\' \
  477. - '....: I am '\''1010'\' \
  478. 'all user-mode processes have quit.' \
  479. 'init check memory pass.'
  480. pts=20
  481. timeout=500
  482. run_test -prog 'matrix' -check default_check \
  483. 'kernel_execve: pid = 2, name = "matrix".' \
  484. 'fork ok.' \
  485. 'pid 4 done!.' \
  486. 'pid 7 done!.' \
  487. 'pid 13 done!.' \
  488. 'pid 17 done!.' \
  489. 'pid 23 done!.' \
  490. 'matrix pass.' \
  491. 'all user-mode processes have quit.' \
  492. 'init check memory pass.' \
  493. ! - 'user panic at .*'
  494. pts=20
  495. timeout=150
  496. run_test -prog 'priority' -check default_check \
  497. 'sched class: stride_scheduler' \
  498. 'kernel_execve: pid = 2, name = "priority".' \
  499. 'main: fork ok,now need to wait pids.' \
  500. 'stride sched correct result: 1 2 3 4 5' \
  501. 'all user-mode processes have quit.' \
  502. 'init check memory pass.' \
  503. ! - 'user panic at .*'
  504. ## print final-score
  505. show_final