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

116 lines
3.2 KiB

10 years ago
  1. #include <defs.h>
  2. #include <x86.h>
  3. #include <elf.h>
  4. /* *********************************************************************
  5. * This a dirt simple boot loader, whose sole job is to boot
  6. * an ELF kernel image from the first IDE hard disk.
  7. *
  8. * DISK LAYOUT
  9. * * This program(bootasm.S and bootmain.c) is the bootloader.
  10. * It should be stored in the first sector of the disk.
  11. *
  12. * * The 2nd sector onward holds the kernel image.
  13. *
  14. * * The kernel image must be in ELF format.
  15. *
  16. * BOOT UP STEPS
  17. * * when the CPU boots it loads the BIOS into memory and executes it
  18. *
  19. * * the BIOS intializes devices, sets of the interrupt routines, and
  20. * reads the first sector of the boot device(e.g., hard-drive)
  21. * into memory and jumps to it.
  22. *
  23. * * Assuming this boot loader is stored in the first sector of the
  24. * hard-drive, this code takes over...
  25. *
  26. * * control starts in bootasm.S -- which sets up protected mode,
  27. * and a stack so C code then run, then calls bootmain()
  28. *
  29. * * bootmain() in this file takes over, reads in the kernel and jumps to it.
  30. * */
  31. #define SECTSIZE 512
  32. #define ELFHDR ((struct elfhdr *)0x10000) // scratch space
  33. /* waitdisk - wait for disk ready */
  34. static void
  35. waitdisk(void) {
  36. while ((inb(0x1F7) & 0xC0) != 0x40)
  37. /* do nothing */;
  38. }
  39. /* readsect - read a single sector at @secno into @dst */
  40. static void
  41. readsect(void *dst, uint32_t secno) {
  42. // wait for disk to be ready
  43. waitdisk();
  44. outb(0x1F2, 1); // count = 1
  45. outb(0x1F3, secno & 0xFF);
  46. outb(0x1F4, (secno >> 8) & 0xFF);
  47. outb(0x1F5, (secno >> 16) & 0xFF);
  48. outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0);
  49. outb(0x1F7, 0x20); // cmd 0x20 - read sectors
  50. // wait for disk to be ready
  51. waitdisk();
  52. // read a sector
  53. insl(0x1F0, dst, SECTSIZE / 4);
  54. }
  55. /* *
  56. * readseg - read @count bytes at @offset from kernel into virtual address @va,
  57. * might copy more than asked.
  58. * */
  59. static void
  60. readseg(uintptr_t va, uint32_t count, uint32_t offset) {
  61. uintptr_t end_va = va + count;
  62. // round down to sector boundary
  63. va -= offset % SECTSIZE;
  64. // translate from bytes to sectors; kernel starts at sector 1
  65. uint32_t secno = (offset / SECTSIZE) + 1;
  66. // If this is too slow, we could read lots of sectors at a time.
  67. // We'd write more to memory than asked, but it doesn't matter --
  68. // we load in increasing order.
  69. for (; va < end_va; va += SECTSIZE, secno ++) {
  70. readsect((void *)va, secno);
  71. }
  72. }
  73. /* bootmain - the entry of bootloader */
  74. void
  75. bootmain(void) {
  76. // read the 1st page off disk
  77. readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
  78. // is this a valid ELF?
  79. if (ELFHDR->e_magic != ELF_MAGIC) {
  80. goto bad;
  81. }
  82. struct proghdr *ph, *eph;
  83. // load each program segment (ignores ph flags)
  84. ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
  85. eph = ph + ELFHDR->e_phnum;
  86. for (; ph < eph; ph ++) {
  87. readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
  88. }
  89. // call the entry point from the ELF header
  90. // note: does not return
  91. ((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
  92. bad:
  93. outw(0x8A00, 0x8A00);
  94. outw(0x8A00, 0x8E00);
  95. /* do nothing */
  96. while (1);
  97. }