protected_mode_thiscouldbebetter.asm 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. ; 2-stage protected mode entry.
  2. ;
  3. ; Initially taken from:
  4. ; https://thiscouldbebetter.wordpress.com/2011/03/17/entering-protected-mode-from-assembly/
  5. ;
  6. ; This works on QEMU, but I don't trust the expertize of that author very much.
  7. ; E.g., this does not have any `[BITS 32]`?
  8. use16
  9. org 0x7C00
  10. mov ah, 0x00
  11. mov dl, 0
  12. int 0x13
  13. mov ah, 0x02
  14. mov al, 0x10
  15. mov dl, 0x80
  16. mov ch, 0
  17. mov dh, 0
  18. mov cl, 2
  19. mov bx, stage2
  20. int 0x13
  21. jmp stage2
  22. times ((0x200 - 2) - ($ - $$)) db 0x00
  23. dw 0xAA55
  24. stage2:
  25. ; Set up data for entering protected mode.
  26. xor edx, edx ; edx = 0
  27. mov dx, ds ; get the data segment
  28. shl edx, 4 ; shift it left a nibble
  29. add [gdt+2], edx ; GDT's base addr = edx
  30. lgdt [gdt] ; load the GDT
  31. mov eax, cr0 ; eax = machine status word (MSW)
  32. or al, 1 ; set the protection enable bit of the MSW to 1
  33. cli
  34. mov cr0, eax ; start protected mode
  35. mov bx, 0x08 ; the size of a GDT descriptor is 8 bytes
  36. mov fs, bx ; fs = the 2nd GDT descriptor, a 4 GB data seg
  37. ; Write a status message.
  38. mov ebx, 0xB8000 ; address of first char for VGA mode 3
  39. mov si, message ; si = message text
  40. for_each_char:
  41. lodsb
  42. cmp al, 0x00
  43. je end_for_each_char
  44. mov [fs:ebx], al
  45. inc ebx
  46. inc ebx
  47. jmp for_each_char
  48. end_for_each_char:
  49. loop_forever:
  50. jmp loop_forever
  51. ret
  52. message: db 'hello world', 0
  53. gdt:
  54. ; the global descriptor table is the heart of protected mode
  55. ; entries are used to map virtual to physical memory
  56. ; among other things
  57. ;
  58. ; each descriptor contains 8 bytes, "organized" as follows:
  59. ;
  60. ; |----------------------2 bytes--------------------|
  61. ;
  62. ; +-------------------------------------------------+
  63. ; | segment address 24-31 | flags #2 | len 16-19 | +6
  64. ; +-------------------------------------------------+
  65. ; | flags #1 | segment address 16-23 | +4
  66. ; +-------------------------------------------------+
  67. ; | segment address bits 0-15 | +2
  68. ; +-------------------------------------------------+
  69. ; | segment length bits 0-15 | +0
  70. ; +-------------------------------------------------+
  71. ; the high-order bit of flags #2 controls "granularity"
  72. ; setting it to 1 multiplies the segment length by 4096
  73. ;======================================================
  74. ; create two descriptors:
  75. ; one for the GDT itself, plus a 4 gibabyte data segment
  76. dw gdt_end - gdt - 1
  77. ; segment address bits 0-15, 16-23
  78. dw gdt
  79. db 0
  80. ; flags 1, segment length 16-19 + flags 2
  81. db 0, 0
  82. ; segment address bits 24-31
  83. db 0
  84. ; a data segment based at address 0, 4 gibabytes long
  85. dw 0xFFFF ; segment length 0-15
  86. db 0, 0, 0 ; segment address 0-15, 16-23
  87. db 0x91 ; flags 1
  88. db 0xCF ; flags 2, segment length 16-19
  89. db 0 ; segment address 24-31
  90. gdt_end:
  91. times (0x2000 - ($ - $$)) db 0x00