Browse files

added all files to repo

  • Loading branch information...
1 parent a123724 commit 1a5f478e08be284f682c59f643e0abf7d73dc28d Abhinav Upadhyay committed Feb 25, 2011
Showing with 18,772 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +95 −0 LICENSE
  3. +56 −0 Make.config
  4. +29 −0 Makefile
  5. +109 −0 Makefile.build
  6. +20 −0 Makefile.kernel
  7. +52 −0 Makefile.userprog
  8. +223 −0 devices/block.c
  9. +74 −0 devices/block.h
  10. +527 −0 devices/ide.c
  11. +6 −0 devices/ide.h
  12. +52 −0 devices/input.c
  13. +12 −0 devices/input.h
  14. +114 −0 devices/intq.c
  15. +43 −0 devices/intq.h
  16. +213 −0 devices/kbd.c
  17. +9 −0 devices/kbd.h
  18. +324 −0 devices/partition.c
  19. +8 −0 devices/partition.h
  20. +83 −0 devices/pit.c
  21. +8 −0 devices/pit.h
  22. +112 −0 devices/rtc.c
  23. +8 −0 devices/rtc.h
  24. +228 −0 devices/serial.c
  25. +11 −0 devices/serial.h
  26. +131 −0 devices/shutdown.c
  27. +19 −0 devices/shutdown.h
  28. +68 −0 devices/speaker.c
  29. +8 −0 devices/speaker.h
  30. +246 −0 devices/timer.c
  31. +29 −0 devices/timer.h
  32. +172 −0 devices/vga.c
  33. +6 −0 devices/vga.h
  34. +19 −0 examples/.gitignore
  35. +34 −0 examples/Makefile
  36. +38 −0 examples/bubsort.c
  37. +34 −0 examples/cat.c
  38. +68 −0 examples/cmp.c
  39. +55 −0 examples/cp.c
  40. +14 −0 examples/echo.c
  41. +14 −0 examples/halt.c
  42. +35 −0 examples/hex-dump.c
  43. +369 −0 examples/insult.c
  44. +1 −0 examples/lib/.gitignore
  45. 0 examples/lib/user/.dummy
  46. +1 −0 examples/lib/user/.gitignore
  47. +46 −0 examples/lineup.c
  48. +90 −0 examples/ls.c
  49. +57 −0 examples/matmult.c
  50. +45 −0 examples/mcat.c
  51. +68 −0 examples/mcp.c
  52. +24 −0 examples/mkdir.c
  53. +152 −0 examples/pwd.c
  54. +34 −0 examples/recursor.c
  55. +21 −0 examples/rm.c
  56. +104 −0 examples/shell.c
  57. +3 −0 filesys/.gitignore
  58. +13 −0 filesys/Make.vars
  59. +1 −0 filesys/Makefile
  60. +236 −0 filesys/directory.c
  61. +30 −0 filesys/directory.h
  62. +168 −0 filesys/file.c
  63. +29 −0 filesys/file.h
  64. +103 −0 filesys/filesys.c
  65. +20 −0 filesys/filesys.h
  66. +85 −0 filesys/free-map.c
  67. +17 −0 filesys/free-map.h
  68. +222 −0 filesys/fsutil.c
  69. +10 −0 filesys/fsutil.h
  70. +345 −0 filesys/inode.c
  71. +23 −0 filesys/inode.h
  72. +15 −0 filesys/off_t.h
  73. +189 −0 lib/arithmetic.c
  74. +28 −0 lib/ctype.h
  75. +32 −0 lib/debug.c
  76. +39 −0 lib/debug.h
  77. +48 −0 lib/inttypes.h
  78. +372 −0 lib/kernel/bitmap.c
  79. +51 −0 lib/kernel/bitmap.h
  80. +191 −0 lib/kernel/console.c
  81. +8 −0 lib/kernel/console.h
  82. +123 −0 lib/kernel/debug.c
  83. +430 −0 lib/kernel/hash.c
  84. +103 −0 lib/kernel/hash.h
  85. +524 −0 lib/kernel/list.c
  86. +181 −0 lib/kernel/list.h
  87. +6 −0 lib/kernel/stdio.h
  88. +34 −0 lib/limits.h
  89. +10 −0 lib/packed.h
  90. +83 −0 lib/random.c
  91. +10 −0 lib/random.h
  92. +18 −0 lib/round.h
  93. +14 −0 lib/stdarg.h
  94. +9 −0 lib/stdbool.h
  95. +12 −0 lib/stddef.h
  96. +51 −0 lib/stdint.h
  97. +655 −0 lib/stdio.c
  98. +40 −0 lib/stdio.h
  99. +208 −0 lib/stdlib.c
  100. +22 −0 lib/stdlib.h
  101. +375 −0 lib/string.c
  102. +35 −0 lib/string.h
  103. +34 −0 lib/syscall-nr.h
  104. +94 −0 lib/user/console.c
  105. +25 −0 lib/user/debug.c
  106. +10 −0 lib/user/entry.c
  107. +7 −0 lib/user/stdio.h
  108. +184 −0 lib/user/syscall.c
  109. +48 −0 lib/user/syscall.h
  110. +57 −0 lib/user/user.lds
  111. +228 −0 lib/ustar.c
  112. +29 −0 lib/ustar.h
  113. +63 −0 misc/bochs-2.2.6-big-endian.patch
  114. +40 −0 misc/bochs-2.2.6-build.sh
  115. +29 −0 misc/bochs-2.2.6-gdbstub-ENN.patch
  116. +61 −0 misc/bochs-2.2.6-jitter.patch
  117. +14 −0 misc/bochs-2.2.6-ms-extensions.patch
  118. +79 −0 misc/bochs-2.2.6-page-fault-segv.patch
  119. +19 −0 misc/bochs-2.2.6-paranoia.patch
  120. +11 −0 misc/bochs-2.2.6-solaris-link.patch
  121. +31 −0 misc/bochs-2.2.6-solaris-tty.patch
  122. +57 −0 misc/bochs-2.2.6-triple-fault.patch
  123. +39 −0 misc/gcc-3.3.6-cross-howto
  124. +140 −0 misc/gdb-macros
  125. +1,713 −0 tests/Algorithm/Diff.pm
  126. +76 −0 tests/Make.tests
  127. +53 −0 tests/arc4.c
  128. +17 −0 tests/arc4.h
  129. +29 −0 tests/arc4.pm
  130. +92 −0 tests/cksum.c
  131. +8 −0 tests/cksum.h
  132. +87 −0 tests/cksum.pm
  133. +18 −0 tests/filesys/Grading.no-vm
  134. +22 −0 tests/filesys/Grading.with-vm
  135. +18 −0 tests/filesys/base/Make.tests
  136. +19 −0 tests/filesys/base/Rubric
  137. +44 −0 tests/filesys/base/child-syn-read.c
  138. +35 −0 tests/filesys/base/child-syn-wrt.c
  139. +20 −0 tests/filesys/base/full.inc
  140. +5 −0 tests/filesys/base/lg-create.c
  141. +13 −0 tests/filesys/base/lg-create.ck
  142. +6 −0 tests/filesys/base/lg-full.c
  143. +16 −0 tests/filesys/base/lg-full.ck
  144. +7 −0 tests/filesys/base/lg-random.c
  145. +14 −0 tests/filesys/base/lg-random.ck
  146. +7 −0 tests/filesys/base/lg-seq-block.c
  147. +16 −0 tests/filesys/base/lg-seq-block.ck
  148. +6 −0 tests/filesys/base/lg-seq-random.c
  149. +16 −0 tests/filesys/base/lg-seq-random.ck
  150. +59 −0 tests/filesys/base/random.inc
  151. +20 −0 tests/filesys/base/seq-block.inc
  152. +22 −0 tests/filesys/base/seq-random.inc
  153. +5 −0 tests/filesys/base/sm-create.c
  154. +13 −0 tests/filesys/base/sm-create.ck
  155. +6 −0 tests/filesys/base/sm-full.c
  156. +16 −0 tests/filesys/base/sm-full.ck
  157. +7 −0 tests/filesys/base/sm-random.c
  158. +14 −0 tests/filesys/base/sm-random.ck
  159. +7 −0 tests/filesys/base/sm-seq-block.c
  160. +16 −0 tests/filesys/base/sm-seq-block.ck
  161. +6 −0 tests/filesys/base/sm-seq-random.c
  162. +16 −0 tests/filesys/base/sm-seq-random.ck
  163. +31 −0 tests/filesys/base/syn-read.c
  164. +33 −0 tests/filesys/base/syn-read.ck
  165. +7 −0 tests/filesys/base/syn-read.h
  166. +30 −0 tests/filesys/base/syn-remove.c
  167. +16 −0 tests/filesys/base/syn-remove.ck
  168. +31 −0 tests/filesys/base/syn-write.c
  169. +32 −0 tests/filesys/base/syn-write.ck
  170. +9 −0 tests/filesys/base/syn-write.h
  171. +15 −0 tests/filesys/create.inc
  172. +61 −0 tests/filesys/extended/Make.tests
  173. +26 −0 tests/filesys/extended/Rubric.functionality
  174. +24 −0 tests/filesys/extended/Rubric.persistence
  175. +9 −0 tests/filesys/extended/Rubric.robustness
  176. +53 −0 tests/filesys/extended/child-syn-rw.c
  177. +6 −0 tests/filesys/extended/dir-empty-name-persistence.ck
  178. +12 −0 tests/filesys/extended/dir-empty-name.c
  179. +10 −0 tests/filesys/extended/dir-empty-name.ck
  180. +16 −0 tests/filesys/extended/dir-mk-tree-persistence.ck
  181. +12 −0 tests/filesys/extended/dir-mk-tree.c
  182. +12 −0 tests/filesys/extended/dir-mk-tree.ck
  183. +6 −0 tests/filesys/extended/dir-mkdir-persistence.ck
  184. +15 −0 tests/filesys/extended/dir-mkdir.c
  185. +13 −0 tests/filesys/extended/dir-mkdir.ck
  186. +6 −0 tests/filesys/extended/dir-open-persistence.ck
  187. +21 −0 tests/filesys/extended/dir-open.c
  188. +20 −0 tests/filesys/extended/dir-open.ck
  189. +6 −0 tests/filesys/extended/dir-over-file-persistence.ck
  190. +13 −0 tests/filesys/extended/dir-over-file.c
  191. +11 −0 tests/filesys/extended/dir-over-file.ck
  192. +8 −0 tests/filesys/extended/dir-rm-cwd-persistence.ck
  193. +75 −0 tests/filesys/extended/dir-rm-cwd.c
  194. +51 −0 tests/filesys/extended/dir-rm-cwd.ck
  195. +6 −0 tests/filesys/extended/dir-rm-parent-persistence.ck
  196. +16 −0 tests/filesys/extended/dir-rm-parent.c
  197. +14 −0 tests/filesys/extended/dir-rm-parent.ck
  198. +6 −0 tests/filesys/extended/dir-rm-root-persistence.ck
  199. +13 −0 tests/filesys/extended/dir-rm-root.c
  200. +11 −0 tests/filesys/extended/dir-rm-root.ck
  201. +6 −0 tests/filesys/extended/dir-rm-tree-persistence.ck
  202. +62 −0 tests/filesys/extended/dir-rm-tree.c
  203. +14 −0 tests/filesys/extended/dir-rm-tree.ck
  204. +6 −0 tests/filesys/extended/dir-rmdir-persistence.ck
  205. +14 −0 tests/filesys/extended/dir-rmdir.c
  206. +12 −0 tests/filesys/extended/dir-rmdir.ck
  207. +6 −0 tests/filesys/extended/dir-under-file-persistence.ck
  208. +13 −0 tests/filesys/extended/dir-under-file.c
  209. +11 −0 tests/filesys/extended/dir-under-file.ck
  210. +37 −0 tests/filesys/extended/dir-vine-persistence.ck
  211. +85 −0 tests/filesys/extended/dir-vine.c
  212. +11 −0 tests/filesys/extended/dir-vine.ck
  213. +6 −0 tests/filesys/extended/grow-create-persistence.ck
  214. +4 −0 tests/filesys/extended/grow-create.c
  215. +13 −0 tests/filesys/extended/grow-create.ck
  216. +9 −0 tests/filesys/extended/grow-dir-lg-persistence.ck
  217. +6 −0 tests/filesys/extended/grow-dir-lg.c
  218. +61 −0 tests/filesys/extended/grow-dir-lg.ck
  219. +41 −0 tests/filesys/extended/grow-dir.inc
  220. +7 −0 tests/filesys/extended/grow-file-size-persistence.ck
  221. +33 −0 tests/filesys/extended/grow-file-size.c
  222. +17 −0 tests/filesys/extended/grow-file-size.ck
  223. +9 −0 tests/filesys/extended/grow-root-lg-persistence.ck
  224. +4 −0 tests/filesys/extended/grow-root-lg.c
  225. +60 −0 tests/filesys/extended/grow-root-lg.ck
  226. +9 −0 tests/filesys/extended/grow-root-sm-persistence.ck
  227. +4 −0 tests/filesys/extended/grow-root-sm.c
  228. +30 −0 tests/filesys/extended/grow-root-sm.ck
  229. +7 −0 tests/filesys/extended/grow-seq-lg-persistence.ck
  230. +5 −0 tests/filesys/extended/grow-seq-lg.c
  231. +17 −0 tests/filesys/extended/grow-seq-lg.ck
  232. +7 −0 tests/filesys/extended/grow-seq-sm-persistence.ck
  233. +5 −0 tests/filesys/extended/grow-seq-sm.c
  234. +17 −0 tests/filesys/extended/grow-seq-sm.ck
  235. +20 −0 tests/filesys/extended/grow-seq.inc
  236. +6 −0 tests/filesys/extended/grow-sparse-persistence.ck
  237. +25 −0 tests/filesys/extended/grow-sparse.c
  238. +17 −0 tests/filesys/extended/grow-sparse.ck
  239. +7 −0 tests/filesys/extended/grow-tell-persistence.ck
  240. +32 −0 tests/filesys/extended/grow-tell.c
  241. +17 −0 tests/filesys/extended/grow-tell.ck
  242. +9 −0 tests/filesys/extended/grow-two-files-persistence.ck
  243. +62 −0 tests/filesys/extended/grow-two-files.c
  244. +23 −0 tests/filesys/extended/grow-two-files.ck
  245. +67 −0 tests/filesys/extended/mk-tree.c
  246. +6 −0 tests/filesys/extended/mk-tree.h
  247. +8 −0 tests/filesys/extended/syn-rw-persistence.ck
  248. +35 −0 tests/filesys/extended/syn-rw.c
  249. +20 −0 tests/filesys/extended/syn-rw.ck
  250. +9 −0 tests/filesys/extended/syn-rw.h
  251. +208 −0 tests/filesys/extended/tar.c
  252. +37 −0 tests/filesys/seq-test.c
  253. +11 −0 tests/filesys/seq-test.h
  254. +174 −0 tests/internal/list.c
  255. +208 −0 tests/internal/stdio.c
  256. +114 −0 tests/internal/stdlib.c
  257. +196 −0 tests/lib.c
  258. +50 −0 tests/lib.h
  259. +19 −0 tests/lib.pm
  260. +15 −0 tests/main.c
  261. +6 −0 tests/main.h
  262. +152 −0 tests/make-grade
  263. +27 −0 tests/random.pm
  264. +625 −0 tests/tests.pm
  265. +6 −0 tests/threads/Grading
  266. +53 −0 tests/threads/Make.tests
  267. +8 −0 tests/threads/Rubric.alarm
  268. +14 −0 tests/threads/Rubric.mlfqs
  269. +15 −0 tests/threads/Rubric.priority
  270. +4 −0 tests/threads/alarm-multiple.ck
  271. +15 −0 tests/threads/alarm-negative.c
  272. +10 −0 tests/threads/alarm-negative.ck
  273. +58 −0 tests/threads/alarm-priority.c
  274. +19 −0 tests/threads/alarm-priority.ck
  275. +94 −0 tests/threads/alarm-simultaneous.c
  276. +27 −0 tests/threads/alarm-simultaneous.ck
  277. +4 −0 tests/threads/alarm-single.ck
  278. +152 −0 tests/threads/alarm-wait.c
  279. +15 −0 tests/threads/alarm-zero.c
  280. +10 −0 tests/threads/alarm-zero.ck
  281. +32 −0 tests/threads/alarm.pm
  282. +64 −0 tests/threads/mlfqs-block.c
  283. +17 −0 tests/threads/mlfqs-block.ck
  284. +7 −0 tests/threads/mlfqs-fair-2.ck
  285. +7 −0 tests/threads/mlfqs-fair-20.ck
  286. +124 −0 tests/threads/mlfqs-fair.c
  287. +60 −0 tests/threads/mlfqs-load-1.c
  288. +15 −0 tests/threads/mlfqs-load-1.ck
  289. +155 −0 tests/threads/mlfqs-load-60.c
  290. +36 −0 tests/threads/mlfqs-load-60.ck
  291. +167 −0 tests/threads/mlfqs-load-avg.c
  292. +36 −0 tests/threads/mlfqs-load-avg.ck
  293. +7 −0 tests/threads/mlfqs-nice-10.ck
  294. +7 −0 tests/threads/mlfqs-nice-2.ck
  295. +144 −0 tests/threads/mlfqs-recent-1.c
  296. +31 −0 tests/threads/mlfqs-recent-1.ck
  297. +146 −0 tests/threads/mlfqs.pm
  298. +31 −0 tests/threads/priority-change.c
  299. +14 −0 tests/threads/priority-change.ck
  300. +53 −0 tests/threads/priority-condvar.c
Sorry, we could not display the entire diff because too many files (608) changed.
View
4 .gitignore
@@ -0,0 +1,4 @@
+cscope.files
+cscope.out
+TAGS
+tags
View
95 LICENSE
@@ -0,0 +1,95 @@
+Pintos, including its documentation, is subject to the following
+license:
+
+ Copyright (C) 2004, 2005, 2006 Board of Trustees, Leland Stanford
+ Jr. University. All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+A few individual files in Pintos were originally derived from other
+projects, but they have been extensively modified for use in Pintos.
+The original code falls under the original license, and modifications
+for Pintos are additionally covered by the Pintos license above.
+
+In particular, code derived from Nachos is subject to the following
+license:
+
+/* Copyright (c) 1992-1996 The Regents of the University of California.
+ All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software
+ and its documentation for any purpose, without fee, and
+ without written agreement is hereby granted, provided that the
+ above copyright notice and the following two paragraphs appear
+ in all copies of this software.
+
+ IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO
+ ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE
+ AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA
+ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+ BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+ MODIFICATIONS.
+*/
+
+Also, code derived from MIT's 6.828 course code is subject to the
+following license:
+
+/*
+ * Copyright (C) 1997 Massachusetts Institute of Technology
+ *
+ * This software is being provided by the copyright holders under the
+ * following license. By obtaining, using and/or copying this software,
+ * you agree that you have read, understood, and will comply with the
+ * following terms and conditions:
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose and without fee or royalty is
+ * hereby granted, provided that the full text of this NOTICE appears on
+ * ALL copies of the software and documentation or portions thereof,
+ * including modifications, that you make.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
+ * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
+ * DOCUMENTATION.
+ *
+ * The name and trademarks of copyright holders may NOT be used in
+ * advertising or publicity pertaining to the software without specific,
+ * written prior permission. Title to copyright in this software and any
+ * associated documentation will at all times remain with copyright
+ * holders. See the file AUTHORS which should have accompanied this software
+ * for a list of all copyright holders.
+ *
+ * This file may be derived from previously copyrighted software. This
+ * copyright applies only to those changes made by the copyright
+ * holders listed in the AUTHORS file. The rest of this file is covered by
+ * the copyright notices, if any, listed below.
+ */
View
56 Make.config
@@ -0,0 +1,56 @@
+# -*- makefile -*-
+
+SHELL = /bin/sh
+
+VPATH = $(SRCDIR)
+
+# Binary utilities.
+# If the host appears to be x86, use the normal tools.
+# If it's x86-64, use the compiler and linker in 32-bit mode.
+# Otherwise assume cross-tools are installed as i386-elf-*.
+X86 = i.86\|pentium.*\|[pk][56]\|nexgen\|viac3\|6x86\|athlon.*\|i86pc
+X86_64 = x86_64
+ifneq (0, $(shell expr `uname -m` : '$(X86)'))
+ CC = gcc
+ LD = ld
+ OBJCOPY = objcopy
+else
+ ifneq (0, $(shell expr `uname -m` : '$(X86_64)'))
+ CC = gcc -m32
+ LD = ld -melf_i386
+ OBJCOPY = objcopy
+ else
+ CC = i386-elf-gcc
+ LD = i386-elf-ld
+ OBJCOPY = i386-elf-objcopy
+ endif
+endif
+
+ifeq ($(strip $(shell command -v $(CC) 2> /dev/null)),)
+$(warning *** Compiler ($(CC)) not found. Did you set $$PATH properly? Please refer to the Getting Started section in the documentation for details. ***)
+endif
+
+# Compiler and assembler invocation.
+DEFINES =
+WARNINGS = -Wall -W -Wstrict-prototypes -Wmissing-prototypes -Wsystem-headers
+CFLAGS = -g -msoft-float -O
+CPPFLAGS = -nostdinc -I$(SRCDIR) -I$(SRCDIR)/lib
+ASFLAGS = -Wa,--gstabs
+LDFLAGS =
+DEPS = -MMD -MF $(@:.o=.d)
+
+# Turn off -fstack-protector, which we don't support.
+ifeq ($(strip $(shell echo | $(CC) -fno-stack-protector -E - > /dev/null 2>&1; echo $$?)),0)
+CFLAGS += -fno-stack-protector
+endif
+
+# Turn off --build-id in the linker, which confuses the Pintos loader.
+ifeq ($(strip $(shell $(LD) --build-id=none -e 0 /dev/null -o /dev/null 2>&1; echo $$?)),0)
+LDFLAGS += -Wl,--build-id=none
+endif
+
+%.o: %.c
+ $(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS) $(WARNINGS) $(DEFINES) $(DEPS)
+
+%.o: %.S
+ $(CC) -c $< -o $@ $(ASFLAGS) $(CPPFLAGS) $(DEFINES) $(DEPS)
View
29 Makefile
@@ -0,0 +1,29 @@
+BUILD_SUBDIRS = threads userprog vm filesys
+
+all::
+ @echo "Run 'make' in subdirectories: $(BUILD_SUBDIRS)."
+ @echo "This top-level make has only 'clean' targets."
+
+CLEAN_SUBDIRS = $(BUILD_SUBDIRS) examples utils
+
+clean::
+ for d in $(CLEAN_SUBDIRS); do $(MAKE) -C $$d $@; done
+ rm -f TAGS tags
+
+distclean:: clean
+ find . -name '*~' -exec rm '{}' \;
+
+TAGS_SUBDIRS = $(BUILD_SUBDIRS) devices lib
+TAGS_SOURCES = find $(TAGS_SUBDIRS) -name \*.[chS] -print
+
+TAGS::
+ etags --members `$(TAGS_SOURCES)`
+
+tags::
+ ctags -T --no-warn `$(TAGS_SOURCES)`
+
+cscope.files::
+ $(TAGS_SOURCES) > cscope.files
+
+cscope:: cscope.files
+ cscope -b -q -k
View
109 Makefile.build
@@ -0,0 +1,109 @@
+# -*- makefile -*-
+
+SRCDIR = ../..
+
+all: kernel.bin loader.bin
+
+include ../../Make.config
+include ../Make.vars
+include ../../tests/Make.tests
+
+# Compiler and assembler options.
+kernel.bin: CPPFLAGS += -I$(SRCDIR)/lib/kernel
+
+# Core kernel.
+threads_SRC = threads/start.S # Startup code.
+threads_SRC += threads/init.c # Main program.
+threads_SRC += threads/thread.c # Thread management core.
+threads_SRC += threads/switch.S # Thread switch routine.
+threads_SRC += threads/interrupt.c # Interrupt core.
+threads_SRC += threads/intr-stubs.S # Interrupt stubs.
+threads_SRC += threads/synch.c # Synchronization.
+threads_SRC += threads/palloc.c # Page allocator.
+threads_SRC += threads/malloc.c # Subpage allocator.
+
+# Device driver code.
+devices_SRC = devices/pit.c # Programmable interrupt timer chip.
+devices_SRC += devices/timer.c # Periodic timer device.
+devices_SRC += devices/kbd.c # Keyboard device.
+devices_SRC += devices/vga.c # Video device.
+devices_SRC += devices/serial.c # Serial port device.
+devices_SRC += devices/block.c # Block device abstraction layer.
+devices_SRC += devices/partition.c # Partition block device.
+devices_SRC += devices/ide.c # IDE disk block device.
+devices_SRC += devices/input.c # Serial and keyboard input.
+devices_SRC += devices/intq.c # Interrupt queue.
+devices_SRC += devices/rtc.c # Real-time clock.
+devices_SRC += devices/shutdown.c # Reboot and power off.
+devices_SRC += devices/speaker.c # PC speaker.
+
+# Library code shared between kernel and user programs.
+lib_SRC = lib/debug.c # Debug helpers.
+lib_SRC += lib/random.c # Pseudo-random numbers.
+lib_SRC += lib/stdio.c # I/O library.
+lib_SRC += lib/stdlib.c # Utility functions.
+lib_SRC += lib/string.c # String functions.
+lib_SRC += lib/arithmetic.c # 64-bit arithmetic for GCC.
+lib_SRC += lib/ustar.c # Unix standard tar format utilities.
+
+# Kernel-specific library code.
+lib/kernel_SRC = lib/kernel/debug.c # Debug helpers.
+lib/kernel_SRC += lib/kernel/list.c # Doubly-linked lists.
+lib/kernel_SRC += lib/kernel/bitmap.c # Bitmaps.
+lib/kernel_SRC += lib/kernel/hash.c # Hash tables.
+lib/kernel_SRC += lib/kernel/console.c # printf(), putchar().
+
+# User process code.
+userprog_SRC = userprog/process.c # Process loading.
+userprog_SRC += userprog/pagedir.c # Page directories.
+userprog_SRC += userprog/exception.c # User exception handler.
+userprog_SRC += userprog/syscall.c # System call handler.
+userprog_SRC += userprog/gdt.c # GDT initialization.
+userprog_SRC += userprog/tss.c # TSS management.
+
+# No virtual memory code yet.
+#vm_SRC = vm/file.c # Some file.
+
+# Filesystem code.
+filesys_SRC = filesys/filesys.c # Filesystem core.
+filesys_SRC += filesys/free-map.c # Free sector bitmap.
+filesys_SRC += filesys/file.c # Files.
+filesys_SRC += filesys/directory.c # Directories.
+filesys_SRC += filesys/inode.c # File headers.
+filesys_SRC += filesys/fsutil.c # Utilities.
+
+SOURCES = $(foreach dir,$(KERNEL_SUBDIRS),$($(dir)_SRC))
+OBJECTS = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SOURCES)))
+DEPENDS = $(patsubst %.o,%.d,$(OBJECTS))
+
+threads/kernel.lds.s: CPPFLAGS += -P
+threads/kernel.lds.s: threads/kernel.lds.S threads/loader.h
+
+kernel.o: threads/kernel.lds.s $(OBJECTS)
+ $(LD) -T $< -o $@ $(OBJECTS)
+
+kernel.bin: kernel.o
+ $(OBJCOPY) -R .note -R .comment -S $< $@
+
+threads/loader.o: threads/loader.S
+ $(CC) -c $< -o $@ $(ASFLAGS) $(CPPFLAGS) $(DEFINES)
+
+loader.bin: threads/loader.o
+ $(LD) -N -e 0 -Ttext 0x7c00 --oformat binary -o $@ $<
+
+os.dsk: kernel.bin
+ cat $^ > $@
+
+clean::
+ rm -f $(OBJECTS) $(DEPENDS)
+ rm -f threads/loader.o threads/kernel.lds.s threads/loader.d
+ rm -f kernel.bin.tmp
+ rm -f kernel.o kernel.lds.s
+ rm -f kernel.bin loader.bin
+ rm -f bochsout.txt bochsrc.txt
+ rm -f results grade
+
+Makefile: $(SRCDIR)/Makefile.build
+ cp $< $@
+
+-include $(DEPENDS)
View
20 Makefile.kernel
@@ -0,0 +1,20 @@
+# -*- makefile -*-
+
+all:
+
+include Make.vars
+
+DIRS = $(sort $(addprefix build/,$(KERNEL_SUBDIRS) $(TEST_SUBDIRS) lib/user))
+
+all grade check: $(DIRS) build/Makefile
+ cd build && $(MAKE) $@
+$(DIRS):
+ mkdir -p $@
+build/Makefile: ../Makefile.build
+ cp $< $@
+
+build/%: $(DIRS) build/Makefile
+ cd build && $(MAKE) $*
+
+clean:
+ rm -rf build
View
52 Makefile.userprog
@@ -0,0 +1,52 @@
+# -*- makefile -*-
+
+$(PROGS): CPPFLAGS += -I$(SRCDIR)/lib/user -I.
+
+# Linker flags.
+$(PROGS): LDFLAGS += -nostdlib -static -Wl,-T,$(LDSCRIPT)
+$(PROGS): LDSCRIPT = $(SRCDIR)/lib/user/user.lds
+
+# Library code shared between kernel and user programs.
+lib_SRC = lib/debug.c # Debug code.
+lib_SRC += lib/random.c # Pseudo-random numbers.
+lib_SRC += lib/stdio.c # I/O library.
+lib_SRC += lib/stdlib.c # Utility functions.
+lib_SRC += lib/string.c # String functions.
+lib_SRC += lib/arithmetic.c # 64-bit arithmetic for GCC.
+lib_SRC += lib/ustar.c # Unix standard tar format utilities.
+
+# User level only library code.
+lib/user_SRC = lib/user/debug.c # Debug helpers.
+lib/user_SRC += lib/user/syscall.c # System calls.
+lib/user_SRC += lib/user/console.c # Console code.
+
+LIB_OBJ = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(lib_SRC) $(lib/user_SRC)))
+LIB_DEP = $(patsubst %.o,%.d,$(LIB_OBJ))
+LIB = lib/user/entry.o libc.a
+
+PROGS_SRC = $(foreach prog,$(PROGS),$($(prog)_SRC))
+PROGS_OBJ = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(PROGS_SRC)))
+PROGS_DEP = $(patsubst %.o,%.d,$(PROGS_OBJ))
+
+all: $(PROGS)
+
+define TEMPLATE
+$(1)_OBJ = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$($(1)_SRC)))
+$(1): $$($(1)_OBJ) $$(LIB) $$(LDSCRIPT)
+ $$(CC) $$(LDFLAGS) $$($(1)_OBJ) $$(LIB) -o $$@
+endef
+
+$(foreach prog,$(PROGS),$(eval $(call TEMPLATE,$(prog))))
+
+libc.a: $(LIB_OBJ)
+ rm -f $@
+ ar r $@ $^
+ ranlib $@
+
+clean::
+ rm -f $(PROGS) $(PROGS_OBJ) $(PROGS_DEP)
+ rm -f $(LIB_DEP) $(LIB_OBJ) lib/user/entry.[do] libc.a
+
+.PHONY: all clean
+
+-include $(LIB_DEP) $(PROGS_DEP)
View
223 devices/block.c
@@ -0,0 +1,223 @@
+#include "devices/block.h"
+#include <list.h>
+#include <string.h>
+#include <stdio.h>
+#include "devices/ide.h"
+#include "threads/malloc.h"
+
+/* A block device. */
+struct block
+ {
+ struct list_elem list_elem; /* Element in all_blocks. */
+
+ char name[16]; /* Block device name. */
+ enum block_type type; /* Type of block device. */
+ block_sector_t size; /* Size in sectors. */
+
+ const struct block_operations *ops; /* Driver operations. */
+ void *aux; /* Extra data owned by driver. */
+
+ unsigned long long read_cnt; /* Number of sectors read. */
+ unsigned long long write_cnt; /* Number of sectors written. */
+ };
+
+/* List of all block devices. */
+static struct list all_blocks = LIST_INITIALIZER (all_blocks);
+
+/* The block block assigned to each Pintos role. */
+static struct block *block_by_role[BLOCK_ROLE_CNT];
+
+static struct block *list_elem_to_block (struct list_elem *);
+
+/* Returns a human-readable name for the given block device
+ TYPE. */
+const char *
+block_type_name (enum block_type type)
+{
+ static const char *block_type_names[BLOCK_CNT] =
+ {
+ "kernel",
+ "filesys",
+ "scratch",
+ "swap",
+ "raw",
+ "foreign",
+ };
+
+ ASSERT (type < BLOCK_CNT);
+ return block_type_names[type];
+}
+
+/* Returns the block device fulfilling the given ROLE, or a null
+ pointer if no block device has been assigned that role. */
+struct block *
+block_get_role (enum block_type role)
+{
+ ASSERT (role < BLOCK_ROLE_CNT);
+ return block_by_role[role];
+}
+
+/* Assigns BLOCK the given ROLE. */
+void
+block_set_role (enum block_type role, struct block *block)
+{
+ ASSERT (role < BLOCK_ROLE_CNT);
+ block_by_role[role] = block;
+}
+
+/* Returns the first block device in kernel probe order, or a
+ null pointer if no block devices are registered. */
+struct block *
+block_first (void)
+{
+ return list_elem_to_block (list_begin (&all_blocks));
+}
+
+/* Returns the block device following BLOCK in kernel probe
+ order, or a null pointer if BLOCK is the last block device. */
+struct block *
+block_next (struct block *block)
+{
+ return list_elem_to_block (list_next (&block->list_elem));
+}
+
+/* Returns the block device with the given NAME, or a null
+ pointer if no block device has that name. */
+struct block *
+block_get_by_name (const char *name)
+{
+ struct list_elem *e;
+
+ for (e = list_begin (&all_blocks); e != list_end (&all_blocks);
+ e = list_next (e))
+ {
+ struct block *block = list_entry (e, struct block, list_elem);
+ if (!strcmp (name, block->name))
+ return block;
+ }
+
+ return NULL;
+}
+
+/* Verifies that SECTOR is a valid offset within BLOCK.
+ Panics if not. */
+static void
+check_sector (struct block *block, block_sector_t sector)
+{
+ if (sector >= block->size)
+ {
+ /* We do not use ASSERT because we want to panic here
+ regardless of whether NDEBUG is defined. */
+ PANIC ("Access past end of device %s (sector=%"PRDSNu", "
+ "size=%"PRDSNu")\n", block_name (block), sector, block->size);
+ }
+}
+
+/* Reads sector SECTOR from BLOCK into BUFFER, which must
+ have room for BLOCK_SECTOR_SIZE bytes.
+ Internally synchronizes accesses to block devices, so external
+ per-block device locking is unneeded. */
+void
+block_read (struct block *block, block_sector_t sector, void *buffer)
+{
+ check_sector (block, sector);
+ block->ops->read (block->aux, sector, buffer);
+ block->read_cnt++;
+}
+
+/* Write sector SECTOR to BLOCK from BUFFER, which must contain
+ BLOCK_SECTOR_SIZE bytes. Returns after the block device has
+ acknowledged receiving the data.
+ Internally synchronizes accesses to block devices, so external
+ per-block device locking is unneeded. */
+void
+block_write (struct block *block, block_sector_t sector, const void *buffer)
+{
+ check_sector (block, sector);
+ ASSERT (block->type != BLOCK_FOREIGN);
+ block->ops->write (block->aux, sector, buffer);
+ block->write_cnt++;
+}
+
+/* Returns the number of sectors in BLOCK. */
+block_sector_t
+block_size (struct block *block)
+{
+ return block->size;
+}
+
+/* Returns BLOCK's name (e.g. "hda"). */
+const char *
+block_name (struct block *block)
+{
+ return block->name;
+}
+
+/* Returns BLOCK's type. */
+enum block_type
+block_type (struct block *block)
+{
+ return block->type;
+}
+
+/* Prints statistics for each block device used for a Pintos role. */
+void
+block_print_stats (void)
+{
+ int i;
+
+ for (i = 0; i < BLOCK_CNT; i++)
+ {
+ struct block *block = block_by_role[i];
+ if (block != NULL)
+ {
+ printf ("%s (%s): %llu reads, %llu writes\n",
+ block->name, block_type_name (block->type),
+ block->read_cnt, block->write_cnt);
+ }
+ }
+}
+
+/* Registers a new block device with the given NAME. If
+ EXTRA_INFO is non-null, it is printed as part of a user
+ message. The block device's SIZE in sectors and its TYPE must
+ be provided, as well as the it operation functions OPS, which
+ will be passed AUX in each function call. */
+struct block *
+block_register (const char *name, enum block_type type,
+ const char *extra_info, block_sector_t size,
+ const struct block_operations *ops, void *aux)
+{
+ struct block *block = malloc (sizeof *block);
+ if (block == NULL)
+ PANIC ("Failed to allocate memory for block device descriptor");
+
+ list_push_back (&all_blocks, &block->list_elem);
+ strlcpy (block->name, name, sizeof block->name);
+ block->type = type;
+ block->size = size;
+ block->ops = ops;
+ block->aux = aux;
+ block->read_cnt = 0;
+ block->write_cnt = 0;
+
+ printf ("%s: %'"PRDSNu" sectors (", block->name, block->size);
+ print_human_readable_size ((uint64_t) block->size * BLOCK_SECTOR_SIZE);
+ printf (")");
+ if (extra_info != NULL)
+ printf (", %s", extra_info);
+ printf ("\n");
+
+ return block;
+}
+
+/* Returns the block device corresponding to LIST_ELEM, or a null
+ pointer if LIST_ELEM is the list end of all_blocks. */
+static struct block *
+list_elem_to_block (struct list_elem *list_elem)
+{
+ return (list_elem != list_end (&all_blocks)
+ ? list_entry (list_elem, struct block, list_elem)
+ : NULL);
+}
+
View
74 devices/block.h
@@ -0,0 +1,74 @@
+#ifndef DEVICES_BLOCK_H
+#define DEVICES_BLOCK_H
+
+#include <stddef.h>
+#include <inttypes.h>
+
+/* Size of a block device sector in bytes.
+ All IDE disks use this sector size, as do most USB and SCSI
+ disks. It's not worth it to try to cater to other sector
+ sizes in Pintos (yet). */
+#define BLOCK_SECTOR_SIZE 512
+
+/* Index of a block device sector.
+ Good enough for devices up to 2 TB. */
+typedef uint32_t block_sector_t;
+
+/* Format specifier for printf(), e.g.:
+ printf ("sector=%"PRDSNu"\n", sector); */
+#define PRDSNu PRIu32
+
+/* Higher-level interface for file systems, etc. */
+
+struct block;
+
+/* Type of a block device. */
+enum block_type
+ {
+ /* Block device types that play a role in Pintos. */
+ BLOCK_KERNEL, /* Pintos OS kernel. */
+ BLOCK_FILESYS, /* File system. */
+ BLOCK_SCRATCH, /* Scratch. */
+ BLOCK_SWAP, /* Swap. */
+ BLOCK_ROLE_CNT,
+
+ /* Other kinds of block devices that Pintos may see but does
+ not interact with. */
+ BLOCK_RAW = BLOCK_ROLE_CNT, /* "Raw" device with unidentified contents. */
+ BLOCK_FOREIGN, /* Owned by non-Pintos operating system. */
+ BLOCK_CNT /* Number of Pintos block types. */
+ };
+
+const char *block_type_name (enum block_type);
+
+/* Finding block devices. */
+struct block *block_get_role (enum block_type);
+void block_set_role (enum block_type, struct block *);
+struct block *block_get_by_name (const char *name);
+
+struct block *block_first (void);
+struct block *block_next (struct block *);
+
+/* Block device operations. */
+block_sector_t block_size (struct block *);
+void block_read (struct block *, block_sector_t, void *);
+void block_write (struct block *, block_sector_t, const void *);
+const char *block_name (struct block *);
+enum block_type block_type (struct block *);
+
+/* Statistics. */
+void block_print_stats (void);
+
+/* Lower-level interface to block device drivers. */
+
+struct block_operations
+ {
+ void (*read) (void *aux, block_sector_t, void *buffer);
+ void (*write) (void *aux, block_sector_t, const void *buffer);
+ };
+
+struct block *block_register (const char *name, enum block_type,
+ const char *extra_info, block_sector_t size,
+ const struct block_operations *, void *aux);
+
+#endif /* devices/block.h */
View
527 devices/ide.c
@@ -0,0 +1,527 @@
+#include "devices/ide.h"
+#include <ctype.h>
+#include <debug.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include "devices/block.h"
+#include "devices/partition.h"
+#include "devices/timer.h"
+#include "threads/io.h"
+#include "threads/interrupt.h"
+#include "threads/synch.h"
+
+/* The code in this file is an interface to an ATA (IDE)
+ controller. It attempts to comply to [ATA-3]. */
+
+/* ATA command block port addresses. */
+#define reg_data(CHANNEL) ((CHANNEL)->reg_base + 0) /* Data. */
+#define reg_error(CHANNEL) ((CHANNEL)->reg_base + 1) /* Error. */
+#define reg_nsect(CHANNEL) ((CHANNEL)->reg_base + 2) /* Sector Count. */
+#define reg_lbal(CHANNEL) ((CHANNEL)->reg_base + 3) /* LBA 0:7. */
+#define reg_lbam(CHANNEL) ((CHANNEL)->reg_base + 4) /* LBA 15:8. */
+#define reg_lbah(CHANNEL) ((CHANNEL)->reg_base + 5) /* LBA 23:16. */
+#define reg_device(CHANNEL) ((CHANNEL)->reg_base + 6) /* Device/LBA 27:24. */
+#define reg_status(CHANNEL) ((CHANNEL)->reg_base + 7) /* Status (r/o). */
+#define reg_command(CHANNEL) reg_status (CHANNEL) /* Command (w/o). */
+
+/* ATA control block port addresses.
+ (If we supported non-legacy ATA controllers this would not be
+ flexible enough, but it's fine for what we do.) */
+#define reg_ctl(CHANNEL) ((CHANNEL)->reg_base + 0x206) /* Control (w/o). */
+#define reg_alt_status(CHANNEL) reg_ctl (CHANNEL) /* Alt Status (r/o). */
+
+/* Alternate Status Register bits. */
+#define STA_BSY 0x80 /* Busy. */
+#define STA_DRDY 0x40 /* Device Ready. */
+#define STA_DRQ 0x08 /* Data Request. */
+
+/* Control Register bits. */
+#define CTL_SRST 0x04 /* Software Reset. */
+
+/* Device Register bits. */
+#define DEV_MBS 0xa0 /* Must be set. */
+#define DEV_LBA 0x40 /* Linear based addressing. */
+#define DEV_DEV 0x10 /* Select device: 0=master, 1=slave. */
+
+/* Commands.
+ Many more are defined but this is the small subset that we
+ use. */
+#define CMD_IDENTIFY_DEVICE 0xec /* IDENTIFY DEVICE. */
+#define CMD_READ_SECTOR_RETRY 0x20 /* READ SECTOR with retries. */
+#define CMD_WRITE_SECTOR_RETRY 0x30 /* WRITE SECTOR with retries. */
+
+/* An ATA device. */
+struct ata_disk
+ {
+ char name[8]; /* Name, e.g. "hda". */
+ struct channel *channel; /* Channel that disk is attached to. */
+ int dev_no; /* Device 0 or 1 for master or slave. */
+ bool is_ata; /* Is device an ATA disk? */
+ };
+
+/* An ATA channel (aka controller).
+ Each channel can control up to two disks. */
+struct channel
+ {
+ char name[8]; /* Name, e.g. "ide0". */
+ uint16_t reg_base; /* Base I/O port. */
+ uint8_t irq; /* Interrupt in use. */
+
+ struct lock lock; /* Must acquire to access the controller. */
+ bool expecting_interrupt; /* True if an interrupt is expected, false if
+ any interrupt would be spurious. */
+ struct semaphore completion_wait; /* Up'd by interrupt handler. */
+
+ struct ata_disk devices[2]; /* The devices on this channel. */
+ };
+
+/* We support the two "legacy" ATA channels found in a standard PC. */
+#define CHANNEL_CNT 2
+static struct channel channels[CHANNEL_CNT];
+
+static struct block_operations ide_operations;
+
+static void reset_channel (struct channel *);
+static bool check_device_type (struct ata_disk *);
+static void identify_ata_device (struct ata_disk *);
+
+static void select_sector (struct ata_disk *, block_sector_t);
+static void issue_pio_command (struct channel *, uint8_t command);
+static void input_sector (struct channel *, void *);
+static void output_sector (struct channel *, const void *);
+
+static void wait_until_idle (const struct ata_disk *);
+static bool wait_while_busy (const struct ata_disk *);
+static void select_device (const struct ata_disk *);
+static void select_device_wait (const struct ata_disk *);
+
+static void interrupt_handler (struct intr_frame *);
+
+/* Initialize the disk subsystem and detect disks. */
+void
+ide_init (void)
+{
+ size_t chan_no;
+
+ for (chan_no = 0; chan_no < CHANNEL_CNT; chan_no++)
+ {
+ struct channel *c = &channels[chan_no];
+ int dev_no;
+
+ /* Initialize channel. */
+ snprintf (c->name, sizeof c->name, "ide%zu", chan_no);
+ switch (chan_no)
+ {
+ case 0:
+ c->reg_base = 0x1f0;
+ c->irq = 14 + 0x20;
+ break;
+ case 1:
+ c->reg_base = 0x170;
+ c->irq = 15 + 0x20;
+ break;
+ default:
+ NOT_REACHED ();
+ }
+ lock_init (&c->lock);
+ c->expecting_interrupt = false;
+ sema_init (&c->completion_wait, 0);
+
+ /* Initialize devices. */
+ for (dev_no = 0; dev_no < 2; dev_no++)
+ {
+ struct ata_disk *d = &c->devices[dev_no];
+ snprintf (d->name, sizeof d->name,
+ "hd%c", 'a' + chan_no * 2 + dev_no);
+ d->channel = c;
+ d->dev_no = dev_no;
+ d->is_ata = false;
+ }
+
+ /* Register interrupt handler. */
+ intr_register_ext (c->irq, interrupt_handler, c->name);
+
+ /* Reset hardware. */
+ reset_channel (c);
+
+ /* Distinguish ATA hard disks from other devices. */
+ if (check_device_type (&c->devices[0]))
+ check_device_type (&c->devices[1]);
+
+ /* Read hard disk identity information. */
+ for (dev_no = 0; dev_no < 2; dev_no++)
+ if (c->devices[dev_no].is_ata)
+ identify_ata_device (&c->devices[dev_no]);
+ }
+}
+
+/* Disk detection and identification. */
+
+static char *descramble_ata_string (char *, int size);
+
+/* Resets an ATA channel and waits for any devices present on it
+ to finish the reset. */
+static void
+reset_channel (struct channel *c)
+{
+ bool present[2];
+ int dev_no;
+
+ /* The ATA reset sequence depends on which devices are present,
+ so we start by detecting device presence. */
+ for (dev_no = 0; dev_no < 2; dev_no++)
+ {
+ struct ata_disk *d = &c->devices[dev_no];
+
+ select_device (d);
+
+ outb (reg_nsect (c), 0x55);
+ outb (reg_lbal (c), 0xaa);
+
+ outb (reg_nsect (c), 0xaa);
+ outb (reg_lbal (c), 0x55);
+
+ outb (reg_nsect (c), 0x55);
+ outb (reg_lbal (c), 0xaa);
+
+ present[dev_no] = (inb (reg_nsect (c)) == 0x55
+ && inb (reg_lbal (c)) == 0xaa);
+ }
+
+ /* Issue soft reset sequence, which selects device 0 as a side effect.
+ Also enable interrupts. */
+ outb (reg_ctl (c), 0);
+ timer_usleep (10);
+ outb (reg_ctl (c), CTL_SRST);
+ timer_usleep (10);
+ outb (reg_ctl (c), 0);
+
+ timer_msleep (150);
+
+ /* Wait for device 0 to clear BSY. */
+ if (present[0])
+ {
+ select_device (&c->devices[0]);
+ wait_while_busy (&c->devices[0]);
+ }
+
+ /* Wait for device 1 to clear BSY. */
+ if (present[1])
+ {
+ int i;
+
+ select_device (&c->devices[1]);
+ for (i = 0; i < 3000; i++)
+ {
+ if (inb (reg_nsect (c)) == 1 && inb (reg_lbal (c)) == 1)
+ break;
+ timer_msleep (10);
+ }
+ wait_while_busy (&c->devices[1]);
+ }
+}
+
+/* Checks whether device D is an ATA disk and sets D's is_ata
+ member appropriately. If D is device 0 (master), returns true
+ if it's possible that a slave (device 1) exists on this
+ channel. If D is device 1 (slave), the return value is not
+ meaningful. */
+static bool
+check_device_type (struct ata_disk *d)
+{
+ struct channel *c = d->channel;
+ uint8_t error, lbam, lbah, status;
+
+ select_device (d);
+
+ error = inb (reg_error (c));
+ lbam = inb (reg_lbam (c));
+ lbah = inb (reg_lbah (c));
+ status = inb (reg_status (c));
+
+ if ((error != 1 && (error != 0x81 || d->dev_no == 1))
+ || (status & STA_DRDY) == 0
+ || (status & STA_BSY) != 0)
+ {
+ d->is_ata = false;
+ return error != 0x81;
+ }
+ else
+ {
+ d->is_ata = (lbam == 0 && lbah == 0) || (lbam == 0x3c && lbah == 0xc3);
+ return true;
+ }
+}
+
+/* Sends an IDENTIFY DEVICE command to disk D and reads the
+ response. Registers the disk with the block device
+ layer. */
+static void
+identify_ata_device (struct ata_disk *d)
+{
+ struct channel *c = d->channel;
+ char id[BLOCK_SECTOR_SIZE];
+ block_sector_t capacity;
+ char *model, *serial;
+ char extra_info[128];
+ struct block *block;
+
+ ASSERT (d->is_ata);
+
+ /* Send the IDENTIFY DEVICE command, wait for an interrupt
+ indicating the device's response is ready, and read the data
+ into our buffer. */
+ select_device_wait (d);
+ issue_pio_command (c, CMD_IDENTIFY_DEVICE);
+ sema_down (&c->completion_wait);
+ if (!wait_while_busy (d))
+ {
+ d->is_ata = false;
+ return;
+ }
+ input_sector (c, id);
+
+ /* Calculate capacity.
+ Read model name and serial number. */
+ capacity = *(uint32_t *) &id[60 * 2];
+ model = descramble_ata_string (&id[10 * 2], 20);
+ serial = descramble_ata_string (&id[27 * 2], 40);
+ snprintf (extra_info, sizeof extra_info,
+ "model \"%s\", serial \"%s\"", model, serial);
+
+ /* Disable access to IDE disks over 1 GB, which are likely
+ physical IDE disks rather than virtual ones. If we don't
+ allow access to those, we're less likely to scribble on
+ someone's important data. You can disable this check by
+ hand if you really want to do so. */
+ if (capacity >= 1024 * 1024 * 1024 / BLOCK_SECTOR_SIZE)
+ {
+ printf ("%s: ignoring ", d->name);
+ print_human_readable_size (capacity * 512);
+ printf ("disk for safety\n");
+ d->is_ata = false;
+ return;
+ }
+
+ /* Register. */
+ block = block_register (d->name, BLOCK_RAW, extra_info, capacity,
+ &ide_operations, d);
+ partition_scan (block);
+}
+
+/* Translates STRING, which consists of SIZE bytes in a funky
+ format, into a null-terminated string in-place. Drops
+ trailing whitespace and null bytes. Returns STRING. */
+static char *
+descramble_ata_string (char *string, int size)
+{
+ int i;
+
+ /* Swap all pairs of bytes. */
+ for (i = 0; i + 1 < size; i += 2)
+ {
+ char tmp = string[i];
+ string[i] = string[i + 1];
+ string[i + 1] = tmp;
+ }
+
+ /* Find the last non-white, non-null character. */
+ for (size--; size > 0; size--)
+ {
+ int c = string[size - 1];
+ if (c != '\0' && !isspace (c))
+ break;
+ }
+ string[size] = '\0';
+
+ return string;
+}
+
+/* Reads sector SEC_NO from disk D into BUFFER, which must have
+ room for BLOCK_SECTOR_SIZE bytes.
+ Internally synchronizes accesses to disks, so external
+ per-disk locking is unneeded. */
+static void
+ide_read (void *d_, block_sector_t sec_no, void *buffer)
+{
+ struct ata_disk *d = d_;
+ struct channel *c = d->channel;
+ lock_acquire (&c->lock);
+ select_sector (d, sec_no);
+ issue_pio_command (c, CMD_READ_SECTOR_RETRY);
+ sema_down (&c->completion_wait);
+ if (!wait_while_busy (d))
+ PANIC ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no);
+ input_sector (c, buffer);
+ lock_release (&c->lock);
+}
+
+/* Write sector SEC_NO to disk D from BUFFER, which must contain
+ BLOCK_SECTOR_SIZE bytes. Returns after the disk has
+ acknowledged receiving the data.
+ Internally synchronizes accesses to disks, so external
+ per-disk locking is unneeded. */
+static void
+ide_write (void *d_, block_sector_t sec_no, const void *buffer)
+{
+ struct ata_disk *d = d_;
+ struct channel *c = d->channel;
+ lock_acquire (&c->lock);
+ select_sector (d, sec_no);
+ issue_pio_command (c, CMD_WRITE_SECTOR_RETRY);
+ if (!wait_while_busy (d))
+ PANIC ("%s: disk write failed, sector=%"PRDSNu, d->name, sec_no);
+ output_sector (c, buffer);
+ sema_down (&c->completion_wait);
+ lock_release (&c->lock);
+}
+
+static struct block_operations ide_operations =
+ {
+ ide_read,
+ ide_write
+ };
+
+/* Selects device D, waiting for it to become ready, and then
+ writes SEC_NO to the disk's sector selection registers. (We
+ use LBA mode.) */
+static void
+select_sector (struct ata_disk *d, block_sector_t sec_no)
+{
+ struct channel *c = d->channel;
+
+ ASSERT (sec_no < (1UL << 28));
+
+ select_device_wait (d);
+ outb (reg_nsect (c), 1);
+ outb (reg_lbal (c), sec_no);
+ outb (reg_lbam (c), sec_no >> 8);
+ outb (reg_lbah (c), (sec_no >> 16));
+ outb (reg_device (c),
+ DEV_MBS | DEV_LBA | (d->dev_no == 1 ? DEV_DEV : 0) | (sec_no >> 24));
+}
+
+/* Writes COMMAND to channel C and prepares for receiving a
+ completion interrupt. */
+static void
+issue_pio_command (struct channel *c, uint8_t command)
+{
+ /* Interrupts must be enabled or our semaphore will never be
+ up'd by the completion handler. */
+ ASSERT (intr_get_level () == INTR_ON);
+
+ c->expecting_interrupt = true;
+ outb (reg_command (c), command);
+}
+
+/* Reads a sector from channel C's data register in PIO mode into
+ SECTOR, which must have room for BLOCK_SECTOR_SIZE bytes. */
+static void
+input_sector (struct channel *c, void *sector)
+{
+ insw (reg_data (c), sector, BLOCK_SECTOR_SIZE / 2);
+}
+
+/* Writes SECTOR to channel C's data register in PIO mode.
+ SECTOR must contain BLOCK_SECTOR_SIZE bytes. */
+static void
+output_sector (struct channel *c, const void *sector)
+{
+ outsw (reg_data (c), sector, BLOCK_SECTOR_SIZE / 2);
+}
+
+/* Low-level ATA primitives. */
+
+/* Wait up to 10 seconds for the controller to become idle, that
+ is, for the BSY and DRQ bits to clear in the status register.
+
+ As a side effect, reading the status register clears any
+ pending interrupt. */
+static void
+wait_until_idle (const struct ata_disk *d)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++)
+ {
+ if ((inb (reg_status (d->channel)) & (STA_BSY | STA_DRQ)) == 0)
+ return;
+ timer_usleep (10);
+ }
+
+ printf ("%s: idle timeout\n", d->name);
+}
+
+/* Wait up to 30 seconds for disk D to clear BSY,
+ and then return the status of the DRQ bit.
+ The ATA standards say that a disk may take as long as that to
+ complete its reset. */
+static bool
+wait_while_busy (const struct ata_disk *d)
+{
+ struct channel *c = d->channel;
+ int i;
+
+ for (i = 0; i < 3000; i++)
+ {
+ if (i == 700)
+ printf ("%s: busy, waiting...", d->name);
+ if (!(inb (reg_alt_status (c)) & STA_BSY))
+ {
+ if (i >= 700)
+ printf ("ok\n");
+ return (inb (reg_alt_status (c)) & STA_DRQ) != 0;
+ }
+ timer_msleep (10);
+ }
+
+ printf ("failed\n");
+ return false;
+}
+
+/* Program D's channel so that D is now the selected disk. */
+static void
+select_device (const struct ata_disk *d)
+{
+ struct channel *c = d->channel;
+ uint8_t dev = DEV_MBS;
+ if (d->dev_no == 1)
+ dev |= DEV_DEV;
+ outb (reg_device (c), dev);
+ inb (reg_alt_status (c));
+ timer_nsleep (400);
+}
+
+/* Select disk D in its channel, as select_device(), but wait for
+ the channel to become idle before and after. */
+static void
+select_device_wait (const struct ata_disk *d)
+{
+ wait_until_idle (d);
+ select_device (d);
+ wait_until_idle (d);
+}
+
+/* ATA interrupt handler. */
+static void
+interrupt_handler (struct intr_frame *f)
+{
+ struct channel *c;
+
+ for (c = channels; c < channels + CHANNEL_CNT; c++)
+ if (f->vec_no == c->irq)
+ {
+ if (c->expecting_interrupt)
+ {
+ inb (reg_status (c)); /* Acknowledge interrupt. */
+ sema_up (&c->completion_wait); /* Wake up waiter. */
+ }
+ else
+ printf ("%s: unexpected interrupt\n", c->name);
+ return;
+ }
+
+ NOT_REACHED ();
+}
+
+
View
6 devices/ide.h
@@ -0,0 +1,6 @@
+#ifndef DEVICES_IDE_H
+#define DEVICES_IDE_H
+
+void ide_init (void);
+
+#endif /* devices/ide.h */
View
52 devices/input.c
@@ -0,0 +1,52 @@
+#include "devices/input.h"
+#include <debug.h>
+#include "devices/intq.h"
+#include "devices/serial.h"
+
+/* Stores keys from the keyboard and serial port. */
+static struct intq buffer;
+
+/* Initializes the input buffer. */
+void
+input_init (void)
+{
+ intq_init (&buffer);
+}
+
+/* Adds a key to the input buffer.
+ Interrupts must be off and the buffer must not be full. */
+void
+input_putc (uint8_t key)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ ASSERT (!intq_full (&buffer));
+
+ intq_putc (&buffer, key);
+ serial_notify ();
+}
+
+/* Retrieves a key from the input buffer.
+ If the buffer is empty, waits for a key to be pressed. */
+uint8_t
+input_getc (void)
+{
+ enum intr_level old_level;
+ uint8_t key;
+
+ old_level = intr_disable ();
+ key = intq_getc (&buffer);
+ serial_notify ();
+ intr_set_level (old_level);
+
+ return key;
+}
+
+/* Returns true if the input buffer is full,
+ false otherwise.
+ Interrupts must be off. */
+bool
+input_full (void)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ return intq_full (&buffer);
+}
View
12 devices/input.h
@@ -0,0 +1,12 @@
+#ifndef DEVICES_INPUT_H
+#define DEVICES_INPUT_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void input_init (void);
+void input_putc (uint8_t);
+uint8_t input_getc (void);
+bool input_full (void);
+
+#endif /* devices/input.h */
View
114 devices/intq.c
@@ -0,0 +1,114 @@
+#include "devices/intq.h"
+#include <debug.h>
+#include "threads/thread.h"
+
+static int next (int pos);
+static void wait (struct intq *q, struct thread **waiter);
+static void signal (struct intq *q, struct thread **waiter);
+
+/* Initializes interrupt queue Q. */
+void
+intq_init (struct intq *q)
+{
+ lock_init (&q->lock);
+ q->not_full = q->not_empty = NULL;
+ q->head = q->tail = 0;
+}
+
+/* Returns true if Q is empty, false otherwise. */
+bool
+intq_empty (const struct intq *q)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ return q->head == q->tail;
+}
+
+/* Returns true if Q is full, false otherwise. */
+bool
+intq_full (const struct intq *q)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ return next (q->head) == q->tail;
+}
+
+/* Removes a byte from Q and returns it.
+ If Q is empty, sleeps until a byte is added.
+ When called from an interrupt handler, Q must not be empty. */
+uint8_t
+intq_getc (struct intq *q)
+{
+ uint8_t byte;
+
+ ASSERT (intr_get_level () == INTR_OFF);
+ while (intq_empty (q))
+ {
+ ASSERT (!intr_context ());
+ lock_acquire (&q->lock);
+ wait (q, &q->not_empty);
+ lock_release (&q->lock);
+ }
+
+ byte = q->buf[q->tail];
+ q->tail = next (q->tail);
+ signal (q, &q->not_full);
+ return byte;
+}
+
+/* Adds BYTE to the end of Q.
+ If Q is full, sleeps until a byte is removed.
+ When called from an interrupt handler, Q must not be full. */
+void
+intq_putc (struct intq *q, uint8_t byte)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ while (intq_full (q))
+ {
+ ASSERT (!intr_context ());
+ lock_acquire (&q->lock);
+ wait (q, &q->not_full);
+ lock_release (&q->lock);
+ }
+
+ q->buf[q->head] = byte;
+ q->head = next (q->head);
+ signal (q, &q->not_empty);
+}
+
+/* Returns the position after POS within an intq. */
+static int
+next (int pos)
+{
+ return (pos + 1) % INTQ_BUFSIZE;
+}
+
+/* WAITER must be the address of Q's not_empty or not_full
+ member. Waits until the given condition is true. */
+static void
+wait (struct intq *q UNUSED, struct thread **waiter)
+{
+ ASSERT (!intr_context ());
+ ASSERT (intr_get_level () == INTR_OFF);
+ ASSERT ((waiter == &q->not_empty && intq_empty (q))
+ || (waiter == &q->not_full && intq_full (q)));
+
+ *waiter = thread_current ();
+ thread_block ();
+}
+
+/* WAITER must be the address of Q's not_empty or not_full
+ member, and the associated condition must be true. If a
+ thread is waiting for the condition, wakes it up and resets
+ the waiting thread. */
+static void
+signal (struct intq *q UNUSED, struct thread **waiter)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ ASSERT ((waiter == &q->not_empty && !intq_empty (q))
+ || (waiter == &q->not_full && !intq_full (q)));
+
+ if (*waiter != NULL)
+ {
+ thread_unblock (*waiter);
+ *waiter = NULL;
+ }
+}
View
43 devices/intq.h
@@ -0,0 +1,43 @@
+#ifndef DEVICES_INTQ_H
+#define DEVICES_INTQ_H
+
+#include "threads/interrupt.h"
+#include "threads/synch.h"
+
+/* An "interrupt queue", a circular buffer shared between
+ kernel threads and external interrupt handlers.
+
+ Interrupt queue functions can be called from kernel threads or
+ from external interrupt handlers. Except for intq_init(),
+ interrupts must be off in either case.
+
+ The interrupt queue has the structure of a "monitor". Locks
+ and condition variables from threads/synch.h cannot be used in
+ this case, as they normally would, because they can only
+ protect kernel threads from one another, not from interrupt
+ handlers. */
+
+/* Queue buffer size, in bytes. */
+#define INTQ_BUFSIZE 64
+
+/* A circular queue of bytes. */
+struct intq
+ {
+ /* Waiting threads. */
+ struct lock lock; /* Only one thread may wait at once. */
+ struct thread *not_full; /* Thread waiting for not-full condition. */
+ struct thread *not_empty; /* Thread waiting for not-empty condition. */
+
+ /* Queue. */
+ uint8_t buf[INTQ_BUFSIZE]; /* Buffer. */
+ int head; /* New data is written here. */
+ int tail; /* Old data is read here. */
+ };
+
+void intq_init (struct intq *);
+bool intq_empty (const struct intq *);
+bool intq_full (const struct intq *);
+uint8_t intq_getc (struct intq *);
+void intq_putc (struct intq *, uint8_t);
+
+#endif /* devices/intq.h */
View
213 devices/kbd.c
@@ -0,0 +1,213 @@
+#include "devices/kbd.h"
+#include <ctype.h>
+#include <debug.h>
+#include <stdio.h>
+#include <string.h>
+#include "devices/input.h"
+#include "devices/shutdown.h"
+#include "threads/interrupt.h"
+#include "threads/io.h"
+
+/* Keyboard data register port. */
+#define DATA_REG 0x60
+
+/* Current state of shift keys.
+ True if depressed, false otherwise. */
+static bool left_shift, right_shift; /* Left and right Shift keys. */
+static bool left_alt, right_alt; /* Left and right Alt keys. */
+static bool left_ctrl, right_ctrl; /* Left and right Ctl keys. */
+
+/* Status of Caps Lock.
+ True when on, false when off. */
+static bool caps_lock;
+
+/* Number of keys pressed. */
+static int64_t key_cnt;
+
+static intr_handler_func keyboard_interrupt;
+
+/* Initializes the keyboard. */
+void
+kbd_init (void)
+{
+ intr_register_ext (0x21, keyboard_interrupt, "8042 Keyboard");
+}
+
+/* Prints keyboard statistics. */
+void
+kbd_print_stats (void)
+{
+ printf ("Keyboard: %lld keys pressed\n", key_cnt);
+}
+
+/* Maps a set of contiguous scancodes into characters. */
+struct keymap
+ {
+ uint8_t first_scancode; /* First scancode. */
+ const char *chars; /* chars[0] has scancode first_scancode,
+ chars[1] has scancode first_scancode + 1,
+ and so on to the end of the string. */
+ };
+
+/* Keys that produce the same characters regardless of whether
+ the Shift keys are down. Case of letters is an exception
+ that we handle elsewhere. */
+static const struct keymap invariant_keymap[] =
+ {
+ {0x01, "\033"}, /* Escape. */
+ {0x0e, "\b"},
+ {0x0f, "\tQWERTYUIOP"},
+ {0x1c, "\r"},
+ {0x1e, "ASDFGHJKL"},
+ {0x2c, "ZXCVBNM"},
+ {0x37, "*"},
+ {0x39, " "},
+ {0x53, "\177"}, /* Delete. */
+ {0, NULL},
+ };
+
+/* Characters for keys pressed without Shift, for those keys
+ where it matters. */
+static const struct keymap unshifted_keymap[] =
+ {
+ {0x02, "1234567890-="},
+ {0x1a, "[]"},
+ {0x27, ";'`"},
+ {0x2b, "\\"},
+ {0x33, ",./"},
+ {0, NULL},
+ };
+
+/* Characters for keys pressed with Shift, for those keys where
+ it matters. */
+static const struct keymap shifted_keymap[] =
+ {
+ {0x02, "!@#$%^&*()_+"},
+ {0x1a, "{}"},
+ {0x27, ":\"~"},
+ {0x2b, "|"},
+ {0x33, "<>?"},
+ {0, NULL},
+ };
+
+static bool map_key (const struct keymap[], unsigned scancode, uint8_t *);
+
+static void
+keyboard_interrupt (struct intr_frame *args UNUSED)
+{
+ /* Status of shift keys. */
+ bool shift = left_shift || right_shift;
+ bool alt = left_alt || right_alt;
+ bool ctrl = left_ctrl || right_ctrl;
+
+ /* Keyboard scancode. */
+ unsigned code;
+
+ /* False if key pressed, true if key released. */
+ bool release;
+
+ /* Character that corresponds to `code'. */
+ uint8_t c;
+
+ /* Read scancode, including second byte if prefix code. */
+ code = inb (DATA_REG);
+ if (code == 0xe0)
+ code = (code << 8) | inb (DATA_REG);
+
+ /* Bit 0x80 distinguishes key press from key release
+ (even if there's a prefix). */
+ release = (code & 0x80) != 0;
+ code &= ~0x80u;
+
+ /* Interpret key. */
+ if (code == 0x3a)
+ {
+ /* Caps Lock. */
+ if (!release)
+ caps_lock = !caps_lock;
+ }
+ else if (map_key (invariant_keymap, code, &c)
+ || (!shift && map_key (unshifted_keymap, code, &c))
+ || (shift && map_key (shifted_keymap, code, &c)))
+ {
+ /* Ordinary character. */
+ if (!release)
+ {
+ /* Reboot if Ctrl+Alt+Del pressed. */
+ if (c == 0177 && ctrl && alt)
+ shutdown_reboot ();
+
+ /* Handle Ctrl, Shift.
+ Note that Ctrl overrides Shift. */
+ if (ctrl && c >= 0x40 && c < 0x60)
+ {
+ /* A is 0x41, Ctrl+A is 0x01, etc. */
+ c -= 0x40;
+ }
+ else if (shift == caps_lock)
+ c = tolower (c);
+
+ /* Handle Alt by setting the high bit.
+ This 0x80 is unrelated to the one used to
+ distinguish key press from key release. */
+ if (alt)
+ c += 0x80;
+
+ /* Append to keyboard buffer. */
+ if (!input_full ())
+ {
+ key_cnt++;
+ input_putc (c);
+ }
+ }
+ }
+ else
+ {
+ /* Maps a keycode into a shift state variable. */
+ struct shift_key
+ {
+ unsigned scancode;
+ bool *state_var;
+ };
+
+ /* Table of shift keys. */
+ static const struct shift_key shift_keys[] =
+ {
+ { 0x2a, &left_shift},
+ { 0x36, &right_shift},
+ { 0x38, &left_alt},
+ {0xe038, &right_alt},
+ { 0x1d, &left_ctrl},
+ {0xe01d, &right_ctrl},
+ {0, NULL},
+ };
+
+ const struct shift_key *key;
+
+ /* Scan the table. */
+ for (key = shift_keys; key->scancode != 0; key++)
+ if (key->scancode == code)
+ {
+ *key->state_var = !release;
+ break;
+ }
+ }
+}
+
+/* Scans the array of keymaps K for SCANCODE.
+ If found, sets *C to the corresponding character and returns
+ true.
+ If not found, returns false and C is ignored. */
+static bool
+map_key (const struct keymap k[], unsigned scancode, uint8_t *c)
+{
+ for (; k->first_scancode != 0; k++)
+ if (scancode >= k->first_scancode
+ && scancode < k->first_scancode + strlen (k->chars))
+ {
+ *c = k->chars[scancode - k->first_scancode];
+ return true;
+ }
+
+ return false;
+}
View
9 devices/kbd.h
@@ -0,0 +1,9 @@
+#ifndef DEVICES_KBD_H
+#define DEVICES_KBD_H
+
+#include <stdint.h>
+
+void kbd_init (void);
+void kbd_print_stats (void);
+
+#endif /* devices/kbd.h */
View
324 devices/partition.c
@@ -0,0 +1,324 @@
+#include "devices/partition.h"
+#include <packed.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "devices/block.h"
+#include "threads/malloc.h"
+
+/* A partition of a block device. */
+struct partition
+ {
+ struct block *block; /* Underlying block device. */
+ block_sector_t start; /* First sector within device. */
+ };
+
+static struct block_operations partition_operations;
+
+static void read_partition_table (struct block *, block_sector_t sector,
+ block_sector_t primary_extended_sector,
+ int *part_nr);
+static void found_partition (struct block *, uint8_t type,
+ block_sector_t start, block_sector_t size,
+ int part_nr);
+static const char *partition_type_name (uint8_t);
+
+/* Scans BLOCK for partitions of interest to Pintos. */
+void
+partition_scan (struct block *block)
+{
+ int part_nr = 0;
+ read_partition_table (block, 0, 0, &part_nr);
+ if (part_nr == 0)
+ printf ("%s: Device contains no partitions\n", block_name (block));
+}
+
+/* Reads the partition table in the given SECTOR of BLOCK and
+ scans it for partitions of interest to Pintos.
+
+ If SECTOR is 0, so that this is the top-level partition table
+ on BLOCK, then PRIMARY_EXTENDED_SECTOR is not meaningful;
+ otherwise, it should designate the sector of the top-level
+ extended partition table that was traversed to arrive at
+ SECTOR, for use in finding logical partitions (see the large
+ comment below).
+
+ PART_NR points to the number of non-empty primary or logical
+ partitions already encountered on BLOCK. It is incremented as
+ partitions are found. */
+static void
+read_partition_table (struct block *block, block_sector_t sector,
+ block_sector_t primary_extended_sector,
+ int *part_nr)
+{
+ /* Format of a partition table entry. See [Partitions]. */
+ struct partition_table_entry
+ {
+ uint8_t bootable; /* 0x00=not bootable, 0x80=bootable. */
+ uint8_t start_chs[3]; /* Encoded starting cylinder, head, sector. */
+ uint8_t type; /* Partition type (see partition_type_name). */
+ uint8_t end_chs[3]; /* Encoded ending cylinder, head, sector. */
+ uint32_t offset; /* Start sector offset from partition table. */
+ uint32_t size; /* Number of sectors. */
+ }
+ PACKED;
+
+ /* Partition table sector. */
+ struct partition_table
+ {
+ uint8_t loader[446]; /* Loader, in top-level partition table. */
+ struct partition_table_entry partitions[4]; /* Table entries. */
+ uint16_t signature; /* Should be 0xaa55. */
+ }
+ PACKED;
+
+ struct partition_table *pt;
+ size_t i;
+
+ /* Check SECTOR validity. */
+ if (sector >= block_size (block))
+ {
+ printf ("%s: Partition table at sector %"PRDSNu" past end of device.\n",
+ block_name (block), sector);
+ return;
+ }
+
+ /* Read sector. */
+ ASSERT (sizeof *pt == BLOCK_SECTOR_SIZE);
+ pt = malloc (sizeof *pt);
+ if (pt == NULL)
+ PANIC ("Failed to allocate memory for partition table.");
+ block_read (block, 0, pt);
+
+ /* Check signature. */
+ if (pt->signature != 0xaa55)
+ {
+ if (primary_extended_sector == 0)
+ printf ("%s: Invalid partition table signature\n", block_name (block));
+ else
+ printf ("%s: Invalid extended partition table in sector %"PRDSNu"\n",
+ block_name (block), sector);
+ free (pt);
+ return;
+ }
+
+ /* Parse partitions. */
+ for (i = 0; i < sizeof pt->partitions / sizeof *pt->partitions; i++)
+ {
+ struct partition_table_entry *e = &pt->partitions[i];
+
+ if (e->size == 0 || e->type == 0)
+ {
+ /* Ignore empty partition. */
+ }
+ else if (e->type == 0x05 /* Extended partition. */
+ || e->type == 0x0f /* Windows 98 extended partition. */
+ || e->type == 0x85 /* Linux extended partition. */
+ || e->type == 0xc5) /* DR-DOS extended partition. */
+ {
+ printf ("%s: Extended partition in sector %"PRDSNu"\n",
+ block_name (block), sector);
+
+ /* The interpretation of the offset field for extended
+ partitions is bizarre. When the extended partition
+ table entry is in the master boot record, that is,
+ the device's primary partition table in sector 0, then
+ the offset is an absolute sector number. Otherwise,
+ no matter how deep the partition table we're reading
+ is nested, the offset is relative to the start of
+ the extended partition that the MBR points to. */
+ if (sector == 0)
+ read_partition_table (block, e->offset, e->offset, part_nr);
+ else
+ read_partition_table (block, e->offset + primary_extended_sector,
+ primary_extended_sector, part_nr);
+ }
+ else
+ {
+ ++*part_nr;
+
+ found_partition (block, e->type, e->offset + sector,
+ e->size, *part_nr);
+ }
+ }
+
+ free (pt);
+}
+
+/* We have found a primary or logical partition of the given TYPE
+ on BLOCK, starting at sector START and continuing for SIZE
+ sectors, which we are giving the partition number PART_NR.
+ Check whether this is a partition of interest to Pintos, and
+ if so then add it to the proper element of partitions[]. */
+static void
+found_partition (struct block *block, uint8_t part_type,
+ block_sector_t start, block_sector_t size,
+ int part_nr)
+{
+ if (start >= block_size (block))
+ printf ("%s%d: Partition starts past end of device (sector %"PRDSNu")\n",
+ block_name (block), part_nr, start);
+ else if (start + size < start || start + size > block_size (block))
+ printf ("%s%d: Partition end (%"PRDSNu") past end of device (%"PRDSNu")\n",
+ block_name (block), part_nr, start + size, block_size (block));
+ else
+ {
+ enum block_type type = (part_type == 0x20 ? BLOCK_KERNEL
+ : part_type == 0x21 ? BLOCK_FILESYS
+ : part_type == 0x22 ? BLOCK_SCRATCH
+ : part_type == 0x23 ? BLOCK_SWAP
+ : BLOCK_FOREIGN);
+ struct partition *p;
+ char extra_info[128];