106 lines
2.9 KiB
ArmAsm
106 lines
2.9 KiB
ArmAsm
/* 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
|