123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- /* https://github.com/cirosantilli/x86-bare-metal-examples#smp */
- /* Must be a multiple of 0x1000. */
- .equ STARTUP_CODE_ADDRESS, 0x1000
- .equ SPINLOCK_ADDRESS, 0x2000
- #include "common.h"
- BEGIN
- STAGE2
- CLEAR
- /* TODO do we need 32-bit mode? I think yes because the APIC register
- * FEE00300 is too high for 16-bit?
- */
- PROTECTED_MODE
- IDT_SETUP_48_ISRS
- REMAP_PIC_32
- PIT_GENERATE_FREQUENCY
- /* Each tick is 20us. */
- PIT_SET_FREQ 50000
- sti
- /* Setup the code that will be run
- * on the other processors when they start up.
- * Should be somewhere into the first 1Mb,
- * as processors start in real mode.
- */
- cld
- mov $init_len, %ecx
- mov $init, %esi
- mov $STARTUP_CODE_ADDRESS, %edi
- rep movsb
- /* Setup the value that threads will modify for us. */
- movb $0, SPINLOCK_ADDRESS
- /* Move data into the lower ICR register:
- * this should start the other processors.
- * - Destination Shorthand = 11 = all except self
- * - Trigger Mode = ?
- * - Level = ?
- * - Delivery Status = 0 = Idle
- * - Destination Mode = ? = Does not matter since shorthand used
- * - Delivery Mode = 110 = Startup
- * - Vector = ? = does it matter for SIPI?
- */
- /* Load address of ICR low dword into ESI. */
- mov PIC_ICR_ADDRESS, %esi
- /* Load ICR encoding for broadcast INIT IPI to all APs. */
- mov $0x000C4500, %eax
- /* Broadcast INIT IPI to all APs */
- mov %eax, (%esi)
- /* 10-millisecond delay loop. */
- PIT_SLEEP_TICKS $500
- /* Load ICR encoding for broadcast SIPI IP to all APs.
- * The low byte of this is the vector which encodes the staring address for the processors!
- * This address is multiplied by 0x1000: processors start at CS = vector * 0x100 and IP = 0.
- */
- mov $0x000C4600 + STARTUP_CODE_ADDRESS / 0x1000, %eax
- /* Broadcast SIPI IPI to all APs. */
- mov %eax, (%esi)
- /* 200-microsecond delay loop. */
- PIT_SLEEP_TICKS $10
- /* Broadcast second SIPI IPI to all APs */
- mov %eax, (%esi)
- /* TODO improve this spinlock. */
- not_started:
- cmpb $1, SPINLOCK_ADDRESS
- jne not_started
- /* This only happens if another thread starts and changes the spinlock.
- * So if we see the message, SMP is working!
- * /
- VGA_PRINT_STRING $message
- /* Testing if it is possible in 16-bit real mode. */
- /*PRINT_STRING $message*/
- hlt
- message:
- .asciz "SMP started"
- IDT_48_ENTRIES
- PIT_SLEEP_TICKS_GLOBALS
- interrupt_handler:
- cmp PIT_ISR_NUMBER, 4(%esp)
- jne not_pit
- PIT_SLEEP_TICKS_HANDLER_UPDATE
- not_pit:
- ret
- /* Code that will run on the second, third,
- * etc. processors (Application Processors),
- */
- .code16
- init:
- xor %ax, %ax
- mov %ax, %ds
- movb $1, SPINLOCK_ADDRESS
- /* TODO mandatory?
- * - is lock prefix enough?
- * - is caching even on? I not because of CR0.CD and CR0.NW
- */
- wbinvd
- hlt
- .equ init_len, . - init
|