PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/branches/0.6/src/osloader/loaderLoadKernel.s

http://ailes.googlecode.com/
Assembly | 528 lines | 305 code | 95 blank | 128 comment | 0 complexity | ce6e907cb128a10280f28b6e9f2d53a0 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. ;;
  2. ;; Copyright (C) 1998-2007 J. Andrew McLaughlin
  3. ;;
  4. ;; This program is free software; you can redistribute it and/or modify it
  5. ;; under the terms of the GNU General Public License as published by the Free
  6. ;; Software Foundation; either version 2 of the License, or (at your option)
  7. ;; any later version.
  8. ;;
  9. ;; This program is distributed in the hope that it will be useful, but
  10. ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. ;; for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU General Public License along
  15. ;; with this program; if not, write to the Free Software Foundation, Inc.,
  16. ;; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. ;;
  18. ;; loaderLoadKernel.s
  19. ;;
  20. GLOBAL loaderLoadKernel
  21. EXTERN loaderLoadFile
  22. EXTERN loaderMemCopy
  23. EXTERN loaderMemSet
  24. EXTERN loaderPrint
  25. EXTERN loaderPrintN
  26. EXTERN loaderPrintNewline
  27. EXTERN loaderPrintNumber
  28. EXTERN KERNELSIZE
  29. EXTERN FILEDATABUFFER
  30. SEGMENT .text
  31. BITS 16
  32. ALIGN 4
  33. %include "loader.h"
  34. getElfHeaderInfo:
  35. ;; This function checks the ELF header of the kernel file and
  36. ;; saves the relevant information about the file.
  37. ;; Save a word for our return code
  38. sub SP, 2
  39. ;; Save regs
  40. pusha
  41. ;; Save the stack register
  42. mov BP, SP
  43. ;; Copy the first sector of the ELF header into the file data buffer
  44. push dword 512
  45. push dword [FILEDATABUFFER]
  46. push dword KERNELCODEDATALOCATION
  47. call loaderMemCopy
  48. add SP, 12
  49. push ES
  50. mov EAX, dword [FILEDATABUFFER]
  51. shr EAX, 4
  52. mov ES, EAX
  53. ;; Make sure it's an ELF file (check the magic number)
  54. mov ESI, 0
  55. mov EAX, dword [ES:ESI]
  56. cmp EAX, 464C457Fh ; ELF magic number (7Fh, 'ELF')
  57. je .isElf
  58. ;; The kernel was not an ELF binary
  59. call loaderPrintNewline
  60. call loaderPrintNewline
  61. call loaderPrintNewline
  62. mov DL, ERRORCOLOR
  63. mov SI, THEFILE
  64. call loaderPrint
  65. mov SI, NOTELF
  66. call loaderPrintN
  67. mov SI, REINSTALL
  68. call loaderPrintN
  69. mov word [SS:(BP + 16)], -1
  70. jmp .done
  71. .isElf:
  72. ;; It's an ELF binary. We will skip doing exhaustive checks, as we
  73. ;; would do in the case of loading some user binary. We will,
  74. ;; however, make sure that it's an executable ELF binary
  75. mov ESI, 16
  76. mov AX, word [ES:ESI]
  77. cmp AX, 2 ; ELF executable file type
  78. je .isExec
  79. ;; The kernel was not executable
  80. call loaderPrintNewline
  81. call loaderPrintNewline
  82. call loaderPrintNewline
  83. mov DL, ERRORCOLOR
  84. mov SI, THEFILE
  85. call loaderPrint
  86. mov SI, NOTEXEC
  87. call loaderPrintN
  88. mov SI, REINSTALL
  89. call loaderPrintN
  90. mov word [SS:(BP + 16)], -2
  91. jmp .done
  92. .isExec:
  93. ;; Cool. Now we start parsing the header, collecting any info
  94. ;; that we care about.
  95. ;; First the kernel entry point.
  96. mov ESI, 24
  97. mov EAX, dword [ES:ESI]
  98. mov dword [ENTRYPOINT], EAX
  99. ;; Now the offset of the program header
  100. mov ESI, 28
  101. mov EAX, dword [ES:ESI]
  102. mov dword [PROGHEADER], EAX
  103. ;; That is all the information we get directly from the ELF header.
  104. ;; Now, we need to get information from the program header.
  105. mov ESI, dword [PROGHEADER]
  106. ;; Skip the segment type.
  107. add ESI, 4
  108. mov EAX, dword [ES:ESI]
  109. mov dword [CODE_OFFSET], EAX
  110. add ESI, 4
  111. mov EAX, dword [ES:ESI]
  112. mov dword [CODE_VIRTADDR], EAX
  113. ;; Skip the physical address.
  114. add ESI, 8
  115. mov EAX, dword [ES:ESI]
  116. mov dword [CODE_SIZEINFILE], EAX
  117. ;; Make sure the size in memory is the same in the file
  118. add ESI, 4
  119. mov EAX, dword [ES:ESI]
  120. cmp EAX, dword [CODE_SIZEINFILE]
  121. je .codeFlags
  122. ;; The kernel image doesn't look the way we expected. This program
  123. ;; isn't versatile enough to handle that yet.
  124. call loaderPrintNewline
  125. call loaderPrintNewline
  126. call loaderPrintNewline
  127. mov DL, ERRORCOLOR
  128. mov SI, THEFILE
  129. call loaderPrint
  130. mov SI, SEGLAYOUT
  131. call loaderPrintN
  132. mov SI, REINSTALL
  133. call loaderPrintN
  134. mov word [SS:(BP + 16)], -3
  135. jmp .done
  136. .codeFlags:
  137. ;; Skip the flags
  138. ;; Just check the alignment. Must be 4096 (page size)
  139. add ESI, 8
  140. mov EAX, dword [ES:ESI]
  141. cmp EAX, 4096
  142. je .dataSeg
  143. ;; The kernel image doesn't look the way we expected. This program
  144. ;; isn't versatile enough to handle that yet.
  145. call loaderPrintNewline
  146. call loaderPrintNewline
  147. call loaderPrintNewline
  148. mov DL, ERRORCOLOR
  149. mov SI, THEFILE
  150. call loaderPrint
  151. mov SI, SEGALIGN
  152. call loaderPrintN
  153. mov SI, REINSTALL
  154. call loaderPrintN
  155. mov word [SS:(BP + 16)], -4
  156. jmp .done
  157. .dataSeg:
  158. ;; Now the data segment
  159. ;; Skip the segment type.
  160. add ESI, 8
  161. mov EAX, dword [ES:ESI]
  162. mov dword [DATA_OFFSET], EAX
  163. add ESI, 4
  164. mov EAX, dword [ES:ESI]
  165. mov dword [DATA_VIRTADDR], EAX
  166. ;; Skip the physical address.
  167. add ESI, 8
  168. mov EAX, dword [ES:ESI]
  169. mov dword [DATA_SIZEINFILE], EAX
  170. add ESI, 4
  171. mov EAX, dword [ES:ESI]
  172. mov dword [DATA_SIZEINMEM], EAX
  173. ;; Skip the flags
  174. add ESI, 8
  175. mov EAX, dword [ES:ESI]
  176. cmp EAX, 4096
  177. je .success
  178. ;; The kernel image doesn't look the way we expected. This program
  179. ;; isn't versatile enough to handle that yet.
  180. call loaderPrintNewline
  181. call loaderPrintNewline
  182. call loaderPrintNewline
  183. mov DL, ERRORCOLOR
  184. mov SI, THEFILE
  185. call loaderPrint
  186. mov SI, SEGALIGN
  187. call loaderPrintN
  188. mov SI, REINSTALL
  189. call loaderPrintN
  190. mov word [SS:(BP + 16)], -5
  191. jmp .done
  192. .success:
  193. ;; Make 0 be our return code
  194. mov word [SS:(BP + 16)], 0
  195. .done:
  196. pop ES
  197. popa
  198. ;; Pop our return code.
  199. xor EAX, EAX
  200. pop AX
  201. ret
  202. layoutKernel:
  203. ;; This function takes information about the kernel ELF file
  204. ;; sections and modifies the kernel image appropriately in memory.
  205. ;; Save regs
  206. pusha
  207. ;; Save the stack register
  208. mov BP, SP
  209. ;; We will do layout for two segments; the code and data segments
  210. ;; (the getElfHeaderInfo() function should have caught any deviation
  211. ;; from that state of affairs).
  212. ;; For the code segment, we simply place it at the entry point. The
  213. ;; entry point, in physical memory, should be KERNELCODEDATALOCATION.
  214. ;; Thus, all we do is move all code forward by CODE_OFFSET bytes.
  215. ;; This will have the side effect of deleting the ELF header and
  216. ;; program header from memory.
  217. mov ECX, dword [CODE_SIZEINFILE]
  218. mov ESI, KERNELCODEDATALOCATION
  219. add ESI, dword [CODE_OFFSET]
  220. mov EDI, KERNELCODEDATALOCATION
  221. push ECX
  222. push EDI
  223. push ESI
  224. call loaderMemCopy
  225. add SP, 12
  226. ;; We do the same operation for the data segment, except we have to
  227. ;; first make sure that the difference between the code and data's
  228. ;; virtual address is the same as the difference between the offsets
  229. ;; in the file.
  230. mov EAX, dword [DATA_VIRTADDR]
  231. sub EAX, dword [CODE_VIRTADDR]
  232. cmp EAX, dword [DATA_OFFSET]
  233. je .okDataOffset
  234. ;; The kernel image doesn't look exactly the way we expected, but
  235. ;; that can happen depending on which linker is used. We can adjust
  236. ;; it. Move the initialized data forward from the original offset
  237. ;; so that it matches the difference between the code and data's
  238. ;; virtual addresses.
  239. mov ECX, dword [DATA_SIZEINFILE]
  240. mov ESI, KERNELCODEDATALOCATION
  241. add ESI, dword [DATA_OFFSET]
  242. mov EDI, dword [DATA_VIRTADDR]
  243. sub EDI, dword [CODE_VIRTADDR]
  244. mov dword [DATA_OFFSET], EDI ;; This will be different now
  245. add EDI, KERNELCODEDATALOCATION
  246. push ECX
  247. push EDI
  248. push ESI
  249. call loaderMemCopy
  250. add SP, 12
  251. .okDataOffset:
  252. ;; We need to zero out the memory that makes up the difference
  253. ;; between the data's file size and its size in memory.
  254. mov ECX, dword [DATA_SIZEINMEM]
  255. sub ECX, dword [DATA_SIZEINFILE]
  256. mov EDI, KERNELCODEDATALOCATION
  257. add EDI, dword [DATA_OFFSET]
  258. add EDI, dword [DATA_SIZEINFILE]
  259. push ECX
  260. push EDI
  261. push word 0
  262. call loaderMemSet
  263. add SP, 10
  264. popa
  265. ret
  266. evaluateLoadError:
  267. ;; This function takes an error code as its only parameter, and
  268. ;; prints the appropriate error message
  269. ;; Save regs
  270. pusha
  271. ;; Save the stack register
  272. mov BP, SP
  273. ;; Use the error color
  274. call loaderPrintNewline
  275. mov DL, ERRORCOLOR
  276. mov SI, LOADFAIL
  277. call loaderPrint
  278. ;; Get the error code
  279. mov AX, word [SS:(BP + 18)]
  280. ;; Was there an error loading the directory?
  281. cmp AX, -1
  282. jne .errorFIND
  283. ;; There was an error loading the directory.
  284. mov SI, NODIRECTORY
  285. call loaderPrintN
  286. mov SI, CORRUPTFS1
  287. call loaderPrintN
  288. mov SI, CORRUPTFS2
  289. call loaderPrintN
  290. jmp .done
  291. .errorFIND:
  292. ;; Was there an error finding the kernel file itself?
  293. cmp AX, -2
  294. jne .errorFAT
  295. ;; The kernel file could not be found.
  296. mov SI, THEFILE
  297. call loaderPrintN
  298. mov SI, NOFILE1
  299. call loaderPrintN
  300. mov SI, NOFILE2
  301. call loaderPrintN
  302. jmp .done
  303. .errorFAT:
  304. ;; Was there an error loading the FAT table?
  305. cmp AX, -3
  306. jne .errorFILE
  307. ;; The FAT table could not be read
  308. mov SI, NOFAT
  309. call loaderPrintN
  310. mov SI, CORRUPTFS1
  311. call loaderPrintN
  312. mov SI, CORRUPTFS2
  313. call loaderPrintN
  314. jmp .done
  315. .errorFILE:
  316. ;; Was there an error loading the kernel file itself?
  317. cmp AX, -4
  318. jne .errorUNKNOWN
  319. mov SI, THEFILE
  320. call loaderPrintN
  321. mov SI, BADFILE
  322. call loaderPrintN
  323. mov SI, CORRUPTFS1
  324. call loaderPrintN
  325. mov SI, CORRUPTFS2
  326. call loaderPrintN
  327. jmp .done
  328. .errorUNKNOWN:
  329. ;; We should really have a proper error message for this.
  330. mov SI, UNKNOWN
  331. call loaderPrintN
  332. .done:
  333. popa
  334. ret
  335. loaderLoadKernel:
  336. ;; This function is in charge of loading the kernel file and
  337. ;; setting it up for execution. This is designed to load the
  338. ;; kernel as an ELF binary. First, it sets up to call the
  339. ;; loaderLoadFile routine with the correct parameters. If there
  340. ;; is an error, it can print an informative error message about
  341. ;; the problem that was encountered (based on the error code from
  342. ;; the loaderLoadFile function). Next, it performs functions
  343. ;; like that of any other 'loader': it examines the ELF header
  344. ;; of the file, does any needed memory spacing as specified therein
  345. ;; (such as moving segments around and creating data segments)
  346. ;; Save a word on the stack for our return value
  347. push word 0
  348. ;; Save regs
  349. pusha
  350. ;; Save the stack register
  351. mov BP, SP
  352. ;; Load the kernel file
  353. push word 1 ; Show progress indicator
  354. push dword KERNELCODEDATALOCATION
  355. push word KERNELNAME
  356. call loaderLoadFile
  357. add SP, 8
  358. ;; Make sure the load was successful
  359. cmp EAX, 0
  360. jge near .okLoad
  361. ;; We failed to load the kernel. The following call will determine
  362. ;; the type of error encountered while loading the kernel, and print
  363. ;; a helpful error message about the reason.
  364. push AX
  365. call evaluateLoadError
  366. add SP, 2
  367. ;; Quit
  368. mov word [SS:(BP + 16)], -1
  369. jmp .done
  370. .okLoad:
  371. ;; We were successful. The kernel's size is in AX. Ignore it.
  372. ;; Now we need to examine the elf header.
  373. call getElfHeaderInfo
  374. ;; Make sure the evaluation was successful
  375. cmp AX, 0
  376. jge near .okEval
  377. ;; The kernel image is not what we expected. Return the error
  378. ;; code from the call
  379. mov word [SS:(BP + 16)], AX
  380. jmp .done
  381. .okEval:
  382. ;; OK, call the routine to create the proper layout for the kernel
  383. ;; based on the ELF information we gathered
  384. call layoutKernel
  385. ;; Set the size of the kernel image, which is the combined memory
  386. ;; size of the code and data segments. Return 0
  387. mov EAX, dword [CODE_SIZEINFILE]
  388. add EAX, dword [DATA_SIZEINMEM]
  389. ;; Make it the next multiple of 4K
  390. add EAX, 00001000h
  391. and EAX, 0FFFFF000h
  392. mov dword [KERNELSIZE], EAX
  393. mov word [SS:(BP + 16)], 0
  394. .done:
  395. ;; Restore regs
  396. popa
  397. ;; Pop our return code
  398. pop AX
  399. ret
  400. ;;
  401. ;; The data segment
  402. ;;
  403. SEGMENT .data
  404. ALIGN 4
  405. ENTRYPOINT dd 0
  406. PROGHEADER dd 0
  407. CODE_OFFSET dd 0
  408. CODE_VIRTADDR dd 0
  409. CODE_SIZEINFILE dd 0
  410. DATA_OFFSET dd 0
  411. DATA_VIRTADDR dd 0
  412. DATA_SIZEINFILE dd 0
  413. DATA_SIZEINMEM dd 0
  414. KERNELNAME db 'ALKRNL ', 0
  415. ;;
  416. ;; The error messages
  417. ;;
  418. LOADFAIL db 'Loading the kernel failed. ', 0
  419. NODIRECTORY db 'The root directory could not be read.', 0
  420. NOFAT db 'The FAT table could not be read.', 0
  421. THEFILE db 'The kernel file ', 0
  422. NOFILE1 db 'could not be found.', 0
  423. NOFILE2 db 'Please make sure that this file exists in the root directory.', 0
  424. BADFILE db 'could not be read.', 0
  425. CORRUPTFS1 db 'The filesystem on the boot device may be corrupt: you should use a disk', 0
  426. CORRUPTFS2 db 'utility to check the integrity of the filesystem.', 0
  427. NOTELF db ' is not an ELF binary.', 0
  428. NOTEXEC db ' is not executable.', 0
  429. NUMSEGS db ' does not contain exactly 2 ELF segments.', 0
  430. SEGALIGN db ' has incorrectly aligned ELF segments.', 0
  431. SEGLAYOUT db ' has an incorrect ELF segment layout.', 0
  432. REINSTALL db 'You will probably need to reinstall the system on this boot media.', 0
  433. UNKNOWN db 'The error code is unknown.', 0