smp.S 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /* https://github.com/cirosantilli/x86-bare-metal-examples#smp */
  2. /* Must be a multiple of 0x1000. */
  3. .equ STARTUP_CODE_ADDRESS, 0x1000
  4. .equ SPINLOCK_ADDRESS, 0x2000
  5. #include "common.h"
  6. BEGIN
  7. STAGE2
  8. CLEAR
  9. /* TODO do we need 32-bit mode? I think yes because the APIC register
  10. * FEE00300 is too high for 16-bit?
  11. */
  12. PROTECTED_MODE
  13. IDT_SETUP_48_ISRS
  14. REMAP_PIC_32
  15. PIT_GENERATE_FREQUENCY
  16. /* Each tick is 20us. */
  17. PIT_SET_FREQ 50000
  18. sti
  19. /* Setup the code that will be run
  20. * on the other processors when they start up.
  21. * Should be somewhere into the first 1Mb,
  22. * as processors start in real mode.
  23. */
  24. cld
  25. mov $init_len, %ecx
  26. mov $init, %esi
  27. mov $STARTUP_CODE_ADDRESS, %edi
  28. rep movsb
  29. /* Setup the value that threads will modify for us. */
  30. movb $0, SPINLOCK_ADDRESS
  31. /* Move data into the lower ICR register:
  32. * this should start the other processors.
  33. * - Destination Shorthand = 11 = all except self
  34. * - Trigger Mode = ?
  35. * - Level = ?
  36. * - Delivery Status = 0 = Idle
  37. * - Destination Mode = ? = Does not matter since shorthand used
  38. * - Delivery Mode = 110 = Startup
  39. * - Vector = ? = does it matter for SIPI?
  40. */
  41. /* Load address of ICR low dword into ESI. */
  42. mov PIC_ICR_ADDRESS, %esi
  43. /* Load ICR encoding for broadcast INIT IPI to all APs. */
  44. mov $0x000C4500, %eax
  45. /* Broadcast INIT IPI to all APs */
  46. mov %eax, (%esi)
  47. /* 10-millisecond delay loop. */
  48. PIT_SLEEP_TICKS $500
  49. /* Load ICR encoding for broadcast SIPI IP to all APs.
  50. * The low byte of this is the vector which encodes the staring address for the processors!
  51. * This address is multiplied by 0x1000: processors start at CS = vector * 0x100 and IP = 0.
  52. */
  53. mov $0x000C4600 + STARTUP_CODE_ADDRESS / 0x1000, %eax
  54. /* Broadcast SIPI IPI to all APs. */
  55. mov %eax, (%esi)
  56. /* 200-microsecond delay loop. */
  57. PIT_SLEEP_TICKS $10
  58. /* Broadcast second SIPI IPI to all APs */
  59. mov %eax, (%esi)
  60. /* TODO improve this spinlock. */
  61. not_started:
  62. cmpb $1, SPINLOCK_ADDRESS
  63. jne not_started
  64. /* This only happens if another thread starts and changes the spinlock.
  65. * So if we see the message, SMP is working!
  66. * /
  67. VGA_PRINT_STRING $message
  68. /* Testing if it is possible in 16-bit real mode. */
  69. /*PRINT_STRING $message*/
  70. hlt
  71. message:
  72. .asciz "SMP started"
  73. IDT_48_ENTRIES
  74. PIT_SLEEP_TICKS_GLOBALS
  75. interrupt_handler:
  76. cmp PIT_ISR_NUMBER, 4(%esp)
  77. jne not_pit
  78. PIT_SLEEP_TICKS_HANDLER_UPDATE
  79. not_pit:
  80. ret
  81. /* Code that will run on the second, third,
  82. * etc. processors (Application Processors),
  83. */
  84. .code16
  85. init:
  86. xor %ax, %ax
  87. mov %ax, %ds
  88. movb $1, SPINLOCK_ADDRESS
  89. /* TODO mandatory?
  90. * - is lock prefix enough?
  91. * - is caching even on? I not because of CR0.CD and CR0.NW
  92. */
  93. wbinvd
  94. hlt
  95. .equ init_len, . - init