Skip to content

Commit

Permalink
Calculates stack address for current AP from LAPIC id and use it call…
Browse files Browse the repository at this point in the history
… smp_finish_initialization C code. Introcuded spin lock to synchronize smp_bits and printing messages from initializing APs. Clears identity mapping when SMP initialization is finished.
  • Loading branch information
shoily committed Oct 19, 2020
1 parent b7b9325 commit 2883539
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 18 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ gcc -m32 -std=gnu99 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nosta
gcc -m32 -std=gnu99 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -ffreestanding -fno-pic -Wall -Wextra -Werror -c memory.c -o memory.o<br>
gcc -m32 -std=gnu99 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -ffreestanding -fno-pic -Wall -Wextra -Werror -c page32.c -o page32.o<br>
gcc -m32 -std=gnu99 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -ffreestanding -fno-pic -Wall -Wextra -Werror -c usermode.c -o usermode.o<br>
gcc -m32 -std=gnu99 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -ffreestanding -fno-pic -Wall -Wextra -Werror -c lock.c -o lock.o<br>


ld -static -T kernel32.ld -m elf_i386 -nostdlib --nmagic boot32.o util.o system.o apic.o smp.o setup32.o handlr32.o memory.o page32.o usermode.o start.o -o xiskernel.elf<br>
ld -static -T kernel32.ld -m elf_i386 -nostdlib --nmagic boot32.o util.o system.o apic.o smp.o setup32.o handlr32.o memory.o page32.o usermode.o lock.o start.o -o xiskernel.elf<br>
objcopy -O binary xiskernel.elf xiskernel.bin<br>

<b>Instructions for building boot loader -</b><br>
cat krnlconst.hdr | awk '{print ".equ " $1 ", " $2};' > krnlconst.S<br>
echo ".equ KERNEL_SIZE, &#96;ls -l xiskernel.bin | cut -f5 -d\ &#96;" > krnlsize.h<br>
as --32 bootldr.S -o bootldr.o<br>
ld -static -T bootldr.ld -m elf_i386 -nostdlib --nmagic -o bootldr.elf bootldr.o<br>
Expand Down
2 changes: 1 addition & 1 deletion boot32.S
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
.code32
.text

.equ KERNEL_VIRT_ADDR, 0x80000000
.include "krnlconst.S"
.equ KERNEL_PGDIR_ENTRY, (KERNEL_VIRT_ADDR >> 20)

.globl _start
Expand Down
3 changes: 1 addition & 2 deletions kernel32.ld
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ SECTIONS
_kernel_pg_table_0 = _kernel_pg_dir + 0x1000;
_kernel_stack_0 = _kernel_pg_table_0 + 0x1000;
_kernel_stack_0_start = _kernel_stack_0 + 0x2000;
_kernel_stack_ap_start = _kernel_stack_0_start + (0x2000 * 32);
_kernel_private_data = _kernel_stack_0_start + 8;
_kernel_private_data = _kernel_stack_0_start + (0x2000 * 32);
_kernel_heap_start = (_kernel_private_data + 0x1000) & ~(0xfff);
}
1 change: 1 addition & 0 deletions krnlconst.hdr
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ AP_FIRST_STACK 0xfff0
AP_LAPIC_BASE_REGISTER 0xfff4
AP_COUNT_PHYS_ADDR 0xfff8
AP_KERNEL_PG_DIR 0xfffc
AP_FINISH_CODE 0x10000
KERNEL_VIRT_ADDR 0x80000000
32 changes: 32 additions & 0 deletions lock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*****************************************************************************/
/* File: lock.c */
/* */
/* Description: Source file for synchonization primitives. */
/* */
/* Author: Shoily O Rahman <[email protected]> */
/* */
/* Date: Oct 16, 2020 */
/* */
/*****************************************************************************/

#include "lock.h"

void spinlock_lock(spin_lock *lock) {

__asm__ __volatile__("movl $1, %%eax;"
"1:;"
"lock xchgl %0, %%eax;"
"testl %%eax, %%eax;"
"jne 1b;"
: "=m" (lock->val)
: "m" (lock->val)
: "%eax", "%ebx", "cc", "memory" );
}

void spinlock_unlock(spin_lock *lock) {

__asm__ __volatile__("movl $0, %0;"
: "=m" (lock->val)
:
: "cc", "memory" );
}
24 changes: 24 additions & 0 deletions lock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*****************************************************************************/
/* File: lock.h */
/* */
/* Description: Header file for synchonization primitives. */
/* */
/* Author: Shoily O Rahman <[email protected]> */
/* */
/* Date: Oct 16, 2020 */
/* */
/*****************************************************************************/

#ifndef _LOCK_H
#define _LOCK_H

typedef struct _spin_lock {
int val;
} spin_lock;

#define INIT_SPIN_LOCK(spinlock) memset(spinlock, sizeof(spin_lock), 0)

void spinlock_lock(spin_lock *lock);
void spinlock_unlock(spin_lock *lock);

#endif
42 changes: 33 additions & 9 deletions mpinit.S
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ _start:
cli

// jump to protected mode
ljmpl *codesegaddr
ljmpl *protectmodecodesegaddr

// protected mode code
.code32
Expand All @@ -52,29 +52,49 @@ protectedmodeaddress:
movl %eax, %fs
movl %eax, %gs


// turning on paging
movl AP_KERNEL_PG_DIR, %eax
movl %eax, %cr3
movl %cr0, %eax
orl $0x80000000, %eax
movl %eax, %cr0

lock incw AP_COUNT_PHYS_ADDR+KERNEL_VIRT_ADDR

hlt
ljmpl *highcodesegaddr

.code32
.section ".high", "ax"

highaddress:

// get LAPIC id
movl AP_LAPIC_BASE_REGISTER, %ebx
addl $0x20, %ebx
movl (%ebx), %eax
shrl $24, %eax
movl %eax, %ecx

// calculate start of kernel mode stack for this processor
movl $0x2000, %ebx
mull %ebx
movl AP_FIRST_STACK, %ebx
addl %ebx, %eax

// initialize protected mode stack
movl $PROTECTED_MODE_STACK, %eax
movl %eax, %esp
movl %eax, %ebp
movl %esp, %ebp

pushl %ecx

hlt
// increment AP count
lock incw AP_COUNT_PHYS_ADDR+KERNEL_VIRT_ADDR

movl AP_FINISH_CODE+KERNEL_VIRT_ADDR, %eax

// call finish_mp_initialization
call *%eax

loop:
jmp loop

.data
// global descriptor table (GDT)
Expand Down Expand Up @@ -103,10 +123,14 @@ data_seg_addr:

end_of_gdt:

codesegaddr:
protectmodecodesegaddr:
.long protectedmodeaddress
.word code_seg

highcodesegaddr:
.long highaddress
.word code_seg

gdtdescriptor:
.word end_of_gdt-gdt-1
.long gdt
Expand Down
34 changes: 30 additions & 4 deletions smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "system.h"
#include "apic.h"
#include "krnlconst.h"
#include "lock.h"

#define AP_INIT_PHYS_TEXT 0x7c00

Expand All @@ -21,10 +22,25 @@ extern int init_ap_size;

extern int lapic_base_register;

extern int _kernel_stack_ap_start;
extern int _kernel_pg_dir;
extern int _kernel_pg_table_0;

extern int _kernel_stack_0_start;

int smp_bits = 0;

spin_lock spinlock_smp;

void finish_smp_initialization(int lapic_id) {

spinlock_lock(&spinlock_smp);

smp_bits |= 1 << lapic_id;
print_msg("Init SMP lapic id", lapic_id, 16, false);

spinlock_unlock(&spinlock_smp);
}

void copy_smp_init_to_low_mem() {

char *s = (char*)&init_ap;
Expand All @@ -39,19 +55,22 @@ void copy_smp_init_to_low_mem() {

void smp_start() {

INIT_SPIN_LOCK(&spinlock_smp);

copy_smp_init_to_low_mem();

// initialize AP processor count with 0
// it will be increased by AP startup code
*(int*)(AP_COUNT_PHYS_ADDR+KERNEL_VIRT_ADDR) = 0;
*(int*)(AP_FIRST_STACK+KERNEL_VIRT_ADDR) = (int)&_kernel_stack_ap_start;
*(int*)(AP_LAPIC_BASE_REGISTER+KERNEL_VIRT_ADDR) = (int)&lapic_base_register;
*(int*)(AP_FIRST_STACK+KERNEL_VIRT_ADDR) = (int)&_kernel_stack_0_start;
*(int*)(AP_LAPIC_BASE_REGISTER+KERNEL_VIRT_ADDR) = (int)lapic_base_register;
*(int*)(AP_KERNEL_PG_DIR+KERNEL_VIRT_ADDR) = (((int)&_kernel_pg_dir)-KERNEL_VIRT_ADDR);
*(int*)(AP_FINISH_CODE+KERNEL_VIRT_ADDR) = (int)finish_smp_initialization;

// identity mapping to enable APs to use paging.
// It needs to be cleared after APs are initialized or it usermode programs
// sharing this page directory cannot access first 4MB virtual memory.
((int*)&_kernel_pg_dir)[0] = (((int)&_kernel_pg_table_0) - KERNEL_VIRT_ADDR) | 3;
((int*)&_kernel_pg_dir)[0] = (((int)&_kernel_pg_table_0) - KERNEL_VIRT_ADDR) | 1;

MFENCE;

Expand All @@ -65,5 +84,12 @@ void smp_start() {
write_lapic_register(LAPIC_ICR_2, 0);
pit_wait_ms(200);

// clear identity mapping
((int*)&_kernel_pg_dir)[0] = 0;
__asm__ __volatile__("invlpg (0);"
: : :
);

print_msg("Number of APs", *(int*)(AP_COUNT_PHYS_ADDR+KERNEL_VIRT_ADDR), 10, true);
print_msg("SMP bits", smp_bits, 16, true);
}

0 comments on commit 2883539

Please sign in to comment.