smp.S 2.8 KB

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