《操作系统》的实验代码。

107 行
4.1 KiB

  1. #include <asm.h>
  2. # Start the CPU: switch to 32-bit protected mode, jump into C.
  3. # The BIOS loads this code from the first sector of the hard disk into
  4. # memory at physical address 0x7c00 and starts executing in real mode
  5. # with %cs=0 %ip=7c00.
  6. .set PROT_MODE_CSEG, 0x8 # kernel code segment selector
  7. .set PROT_MODE_DSEG, 0x10 # kernel data segment selector
  8. .set CR0_PE_ON, 0x1 # protected mode enable flag
  9. .set SMAP, 0x534d4150
  10. # start address should be 0:7c00, in real mode, the beginning address of the running bootloader
  11. .globl start
  12. start:
  13. .code16 # Assemble for 16-bit mode
  14. cli # Disable interrupts
  15. cld # String operations increment
  16. # Set up the important data segment registers (DS, ES, SS).
  17. xorw %ax, %ax # Segment number zero
  18. movw %ax, %ds # -> Data Segment
  19. movw %ax, %es # -> Extra Segment
  20. movw %ax, %ss # -> Stack Segment
  21. # Enable A20:
  22. # For backwards compatibility with the earliest PCs, physical
  23. # address line 20 is tied low, so that addresses higher than
  24. # 1MB wrap around to zero by default. This code undoes this.
  25. seta20.1:
  26. inb $0x64, %al # Wait for not busy(8042 input buffer empty).
  27. testb $0x2, %al
  28. jnz seta20.1
  29. movb $0xd1, %al # 0xd1 -> port 0x64
  30. outb %al, $0x64 # 0xd1 means: write data to 8042's P2 port
  31. seta20.2:
  32. inb $0x64, %al # Wait for not busy(8042 input buffer empty).
  33. testb $0x2, %al
  34. jnz seta20.2
  35. movb $0xdf, %al # 0xdf -> port 0x60
  36. outb %al, $0x60 # 0xdf = 11011111, means set P2's A20 bit(the 1 bit) to 1
  37. probe_memory:
  38. movl $0, 0x8000
  39. xorl %ebx, %ebx
  40. movw $0x8004, %di
  41. start_probe:
  42. movl $0xE820, %eax
  43. movl $20, %ecx
  44. movl $SMAP, %edx
  45. int $0x15
  46. jnc cont
  47. movw $12345, 0x8000
  48. jmp finish_probe
  49. cont:
  50. addw $20, %di
  51. incl 0x8000
  52. cmpl $0, %ebx
  53. jnz start_probe
  54. finish_probe:
  55. # Switch from real to protected mode, using a bootstrap GDT
  56. # and segment translation that makes virtual addresses
  57. # identical to physical addresses, so that the
  58. # effective memory map does not change during the switch.
  59. lgdt gdtdesc
  60. movl %cr0, %eax
  61. orl $CR0_PE_ON, %eax
  62. movl %eax, %cr0
  63. # Jump to next instruction, but in 32-bit code segment.
  64. # Switches processor into 32-bit mode.
  65. ljmp $PROT_MODE_CSEG, $protcseg
  66. .code32 # Assemble for 32-bit mode
  67. protcseg:
  68. # Set up the protected-mode data segment registers
  69. movw $PROT_MODE_DSEG, %ax # Our data segment selector
  70. movw %ax, %ds # -> DS: Data Segment
  71. movw %ax, %es # -> ES: Extra Segment
  72. movw %ax, %fs # -> FS
  73. movw %ax, %gs # -> GS
  74. movw %ax, %ss # -> SS: Stack Segment
  75. # Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
  76. movl $0x0, %ebp
  77. movl $start, %esp
  78. call bootmain
  79. # If bootmain returns (it shouldn't), loop.
  80. spin:
  81. jmp spin
  82. .data
  83. # Bootstrap GDT
  84. .p2align 2 # force 4 byte alignment
  85. gdt:
  86. SEG_NULLASM # null seg
  87. SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg for bootloader and kernel
  88. SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg for bootloader and kernel
  89. gdtdesc:
  90. .word 0x17 # sizeof(gdt) - 1
  91. .long gdt # address gdt