Files
x86-bare-metal-examples/smp.S

106 lines
2.9 KiB
ArmAsm
Raw Normal View History

/* https://github.com/cirosantilli/x86-bare-metal-examples#smp */
2018-12-04 09:46:27 +00:00
/* Must be a multiple of 0x1000. */
.equ STARTUP_CODE_ADDRESS, 0x1000
.equ SPINLOCK_ADDRESS, 0x2000
2015-11-06 22:05:47 +01:00
#include "common.h"
BEGIN
2015-11-11 12:12:40 +01:00
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
2015-11-11 12:12:40 +01:00
IDT_SETUP_48_ISRS
REMAP_PIC_32
PIT_GENERATE_FREQUENCY
/* Each tick is 20us. */
PIT_SET_FREQ 50000
sti
2015-11-06 22:05:47 +01:00
/* 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
2015-11-06 22:05:47 +01:00
mov $init_len, %ecx
mov $init, %esi
mov $STARTUP_CODE_ADDRESS, %edi
2015-11-06 22:05:47 +01:00
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)
2015-11-11 12:12:40 +01:00
/* 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. */
2015-11-11 12:12:40 +01:00
PIT_SLEEP_TICKS $10
/* Broadcast second SIPI IPI to all APs */
mov %eax, (%esi)
2015-11-06 22:05:47 +01:00
/* TODO improve this spinlock. */
2015-11-06 22:05:47 +01:00
not_started:
cmpb $1, SPINLOCK_ADDRESS
2015-11-06 22:05:47 +01:00
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
2016-04-03 08:40:53 +02:00
/* Testing if it is possible in 16-bit real mode. */
/*PRINT_STRING $message*/
2015-11-06 22:05:47 +01:00
hlt
message:
.asciz "SMP started"
2015-11-11 12:12:40 +01:00
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
2016-04-03 08:40:53 +02:00
/* Code that will run on the second, third,
* etc. processors (Application Processors),
*/
.code16
2015-11-06 22:05:47 +01:00
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
2015-11-06 22:05:47 +01:00
hlt
.equ init_len, . - init