1
0
Fork 0
mirror of https://gitlab.com/bztsrc/bootboot.git synced 2023-02-13 20:54:32 -05:00

SSE and SMP support

This commit is contained in:
bzt 2019-02-08 00:41:34 +01:00
parent b6e1f6f89a
commit a42fd37e81
17 changed files with 470 additions and 123 deletions

View file

@ -1,4 +1,4 @@
Copyright (C) 2017 bzt (bztsrc@gitlab)
Copyright (C) 2017 - 2019 bzt (bztsrc@gitlab)
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

View file

@ -5,11 +5,11 @@ I provide pre-compiled images ready for use.
1. *x86_64-efi* the preferred way of booting on x86_64 architecture.
Standard GNU toolchain and a few files from gnuefi (included).
[bootboot.efi](https://gitlab.com/bztsrc/bootboot/raw/master/bootboot.efi) (93k), [bootboot.rom](https://gitlab.com/bztsrc/bootboot/raw/master/bootboot.rom) (93k)
[bootboot.efi](https://gitlab.com/bztsrc/bootboot/raw/master/bootboot.efi) (94k), [bootboot.rom](https://gitlab.com/bztsrc/bootboot/raw/master/bootboot.rom) (93k)
2. *x86_64-bios* BIOS, Multiboot (GRUB), El Torito (CDROM), Expansion ROM and Linux boot compatible, OBSOLETE loader.
If you want to recompile this, you'll need fasm (not included).
[boot.bin](https://gitlab.com/bztsrc/bootboot/raw/master/boot.bin) (512 bytes, works as MBR, VBR and CDROM boot record too), [bootboot.bin](https://gitlab.com/bztsrc/bootboot/raw/master/bootboot.bin) (10k, loaded by boot.bin, also BBS Expansion ROM and Multiboot compliant)
[boot.bin](https://gitlab.com/bztsrc/bootboot/raw/master/boot.bin) (512 bytes, works as MBR, VBR and CDROM boot record too), [bootboot.bin](https://gitlab.com/bztsrc/bootboot/raw/master/bootboot.bin) (11k, loaded by boot.bin, also BBS Expansion ROM and Multiboot compliant)
3. *aarch64-rpi* ARMv8 boot loader for Raspberry Pi 3
[bootboot.img](https://gitlab.com/bztsrc/bootboot/raw/master/bootboot.img) (30k)
@ -144,7 +144,7 @@ When the kernel gains control, the memory mapping looks like this:
0-16G RAM identity mapped (0x0000000400000000)
```
All infomration is passed at linker defined addresses. No API required at all, therefore the BOOTBOOT Protocol is
All information is passed at linker defined addresses. No API required at all, therefore the BOOTBOOT Protocol is
totally architecture and ABI agnostic. Level 1 expects these symbols at pre-defined addresses you see above, level 2
loaders parse the symbol table in executable to get the actual addresses.
@ -169,7 +169,10 @@ load kernels at -2M, therefore limiting the kernel's size in 2M, including confi
must be more than enough for all micro-kernels. Bss segment is after the text segment, growing upwards, and it's zerod-out
by the loader.
The stack is at the top of the memory, starting at zero and growing downwards.
Co-processor enabled, and if Symmetric Multi Processing supported, all cores are running the same kernel code at once.
The stack is at the top of the memory, starting at zero and growing downwards. Each core has it's own 1k stack on SMP systems
(core 0's stack starts at 0, core 1's at -1024 etc.).
Environment file
----------------
@ -257,6 +260,7 @@ extern uint8_t fb; // linear framebuffer mapped
void _start()
{
/*** NOTE: this code runs on all cores in parallel ***/
int x, y, s=bootboot.fb_scanline, w=bootboot.fb_width, h=bootboot.fb_height;
// cross-hair to see screen dimension detected correctly
@ -279,6 +283,18 @@ void _start()
For compilation, see example bootboot kernel's [Makefile](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel/Makefile) and
[link.ld](https://gitlab.com/bztsrc/bootboot/blob/master/mykernel/link.ld).
Because on an SMP system all cores executing the same code, you probably want to start your kernel with something like:
```c
if (currentcoreid == bootboot.bspid) {
/* things to do on the bootstrap processor */
} else {
/* things to do on the application processor(s) */
}
```
On x86_64, 'currentcoreid' is the Local Apic Id (cpuid[eax=1].ebx >> 24), on AArch64 that's (mpidr_el1 & 3).
Installation
------------

View file

@ -16,8 +16,8 @@ In addition to standard mappings, the MMIO is also mapped in kernel space:
-128M MMIO (0xFFFFFFFFF8000000)
```
Code is running in supervisor mode, at EL1. Dummy exception handlers are installed, but your kernel should use it's own
handlers as soon as possible.
Code is running in supervisor mode, at EL1 on all cores. Dummy exception handlers are installed, but your kernel should use
it's own handlers as soon as possible.
File system drivers
-------------------

View file

@ -1,6 +1,6 @@
/*
* aarch64-rpi/boot.S
*
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
@ -30,7 +30,6 @@
.section ".text.boot"
.global _start
.global jumptokernel
/*********************************************************************
* Entry point called by start.elf *
@ -39,14 +38,8 @@ _start:
// magic
b 1f
.ascii "BOOTBOOT"
// read cpu id, stop slave cores
1: mrs x7, mpidr_el1
and x7, x7, #3
cbz x7, 2f
1: wfe
b 1b
2: // set stack before our code
ldr x1, =_start
// set stack before our code
1: ldr x1, =_start
// set up EL1
mrs x0, CurrentEL
and x0, x0, #12
@ -65,8 +58,8 @@ _start:
beq 1f
msr sp_el1, x1
// set up exception handlers
ldr x1, =_vectors
msr vbar_el2, x1
ldr x2, =_vectors
msr vbar_el2, x2
// enable CNTP for EL1
mrs x0, cnthctl_el2
orr x0, x0, #3
@ -98,7 +91,14 @@ _start:
adr x2, 1f
msr elr_el2, x2
eret
1: // clear bss
// set up exception handlers
1: ldr x2, =_vectors
msr vbar_el1, x2
// read cpu id, start slave cores
mrs x7, mpidr_el1
and x7, x7, #3
cbnz x7, 3f
// clear bss
ldr x2, =__bss_start
ldr w3, =__bss_size
1: cbz w3, 2f
@ -106,13 +106,9 @@ _start:
sub w3, w3, #1
cbnz w3, 1b
2: mov sp, x1
// set up exception handlers
ldr x1, =_vectors
msr vbar_el1, x1
// jump to C code
bl bootboot_main
1: wfe
b 1b
3: b bootboot_startcore
.align 11
_vectors:

View file

@ -1,7 +1,7 @@
/*
* aarch64-rpi/bootboot.c
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
* Copyright (C) 2017 - 2019 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@ -755,6 +755,9 @@ unsigned char *kne;
// alternative environment name
char *cfgname="sys/config";
uint64_t entrypoint=0, bss=0, *paging, reg, pa;
uint8_t bsp_done=0;
#ifdef _FS_Z_H_
/**
* SHA-256
@ -1101,15 +1104,14 @@ void ParseEnvironment(uint8_t *env)
}
/**
* bootboot entry point
* bootboot entry point, run only on BSP core
*/
int bootboot_main(uint64_t hcl)
{
uint8_t *pe,bkp=0;
uint32_t np,sp,r,pa,mp;
uint32_t np,sp,r,mp;
efipart_t *part;
volatile bpb_t *bpb;
uint64_t entrypoint=0, bss=0, *paging, reg;
MMapEnt *mmap;
/* initialize UART */
@ -1165,10 +1167,9 @@ int bootboot_main(uint64_t hcl)
bootboot = (BOOTBOOT*)&__bootboot;
memset(bootboot,0,PAGESIZE);
memcpy((void*)&bootboot->magic,BOOTBOOT_MAGIC,4);
bootboot->protocol = PROTOCOL_STATIC;
bootboot->loader_type = LOADER_RPI;
bootboot->protocol = PROTOCOL_STATIC | LOADER_RPI;
bootboot->size = 128;
bootboot->pagesize = PAGESIZE==4096? 12 : (PAGESIZE==65536 ? 16 : 14);
bootboot->numcores = 4;
bootboot->aarch64.mmio_ptr = COREMMIO_BASE;
// set up a framebuffer so that we can write on screen
if(!GetLFB(0, 0)) goto viderr;
@ -1516,6 +1517,8 @@ gzerr: puts("BOOTBOOT-PANIC: Unable to uncompress\n");
uart_hex((uint64_t)core.ptr+core.size,4);
uart_putc('\n');
#endif
/* we have fixed number of cores, nothing to detect */
DBG(" * SMP numcores 4\n");
/* generate memory map to bootboot struct */
DBG(" * Memory Map\n");
@ -1629,7 +1632,7 @@ viderr:
#if MEM_DEBUG
reg=r;
#endif
paging[5*512+511]=(uint64_t)((uint8_t*)&__corestack)|0b11|(3<<8)|(1<<10)|(1L<<54); // core stack
paging[5*512+511]=(uint64_t)((uint8_t*)&__corestack)|0b11|(3<<8)|(1<<10)|(1L<<54); // core stacks (1k each)
// core L3 (lfb)
for(r=0;r<16*512;r++)
paging[6*512+r]=(uint64_t)((uint8_t*)bootboot->fb_ptr+r*PAGESIZE)|0b11|(2<<8)|(1<<10)|(2<<2)|(1L<<54); //map framebuffer
@ -1677,6 +1680,35 @@ viderr:
for(r=508;r<512;r++) { uart_hex(paging[5*512+r],8); uart_putc(' '); }
uart_puts("\n\n");
#endif
#if DEBUG
uart_puts(" * Entry point ");
uart_hex(entrypoint,8);
uart_putc('\n');
#endif
// release AP spinlock
bsp_done=1;
return 0;
// Wait until Enter or Space pressed, then reboot
error:
while(r!='\n' && r!=' ') r=uart_getc();
uart_puts("\n\n");
// reset
asm volatile("dsb sy; isb");
*PM_WATCHDOG = PM_WDOG_MAGIC | 1;
*PM_RTSC = PM_WDOG_MAGIC | PM_RTSC_FULLRST;
while(1);
}
/**
* start kernel, run on all cores
*/
void bootboot_startcore()
{
// spinlock until BSP finishes
do { asm volatile ("dsb sy"); } while(!bsp_done);
// enable paging
reg=(0xFF << 0) | // Attr=0: normal, IWBWA, OWBWA, NTR
(0x04 << 8) | // Attr=1: device, nGnRE (must be OSH too)
@ -1713,22 +1745,9 @@ viderr:
reg|=(1<<0)/*|(1<<19)|(1<<12)|(1<<2)*/; // set M enable MMU, WXN, I instruction cache, C data cache
asm volatile ("msr sctlr_el1, %0; isb" : : "r" (reg));
// jump to core's _start
#if DEBUG
uart_puts(" * Entry point ");
uart_hex(entrypoint,8);
uart_putc('\n');
#endif
asm volatile ("mov sp,#-16; mov x30, %0; ret" : : "r" (entrypoint));
// Wait until Enter or Space pressed, then reboot
error:
while(r!='\n' && r!=' ') r=uart_getc();
uart_puts("\n\n");
// reset
asm volatile("dsb sy; isb");
*PM_WATCHDOG = PM_WDOG_MAGIC | 1;
*PM_RTSC = PM_WDOG_MAGIC | PM_RTSC_FULLRST;
while(1);
// set stack and call _start() in sys/core
asm volatile ( "mrs x0, mpidr_el1;"
"and x0, x0, #3;"
"sub x0, xzr, x0, lsl #10;" // sp = core_num * -1024
"mov sp, x0; mov x30, %0; ret" : : "r" (entrypoint));
}

Binary file not shown.

Binary file not shown.

View file

@ -1,7 +1,7 @@
/*
* bootboot.h
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
* Copyright (C) 2017 - 2019 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@ -50,9 +50,9 @@ extern "C" {
#define PROTOCOL_BIGENDIAN 0x80
// loader types, just informational
#define LOADER_BIOS 0
#define LOADER_UEFI 1
#define LOADER_RPI 2
#define LOADER_BIOS (0<<2)
#define LOADER_UEFI (1<<2)
#define LOADER_RPI (2<<2)
// framebuffer pixel format, only 32 bits supported
#define FB_ARGB 0
@ -81,22 +81,17 @@ typedef struct {
#define INITRD_MAXSIZE 16 //Mb
typedef struct {
uint8_t magic[4]; // 'BOOT', first 64 bytes are platform independent
// first 64 bytes is platform independent
uint8_t magic[4]; // 'BOOT' magic
uint32_t size; // length of bootboot structure, minimum 128
uint8_t protocol; // 1, static addresses, see PROTOCOL_* above
uint8_t loader_type; // see LOADER_* above
uint8_t pagesize; // in power of two, 12 = 4096
uint8_t protocol; // 1, static addresses, see PROTOCOL_* and LOADER_* above
uint8_t fb_type; // framebuffer type, see FB_* above
uint16_t numcores; // number of processor cores
uint16_t bspid; // Bootsrap processor ID (Local APIC Id on x86_64)
int16_t timezone; // in minutes -1440..1440
uint8_t datetime[8]; // in BCD yyyymmddhhiiss UTC (independent to timezone)
uint64_t initrd_ptr; // ramdisk image position and size
uint64_t initrd_size;
uint8_t *fb_ptr; // framebuffer pointer and dimensions
uint32_t fb_size;
uint32_t fb_width;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -50,6 +50,7 @@ extern uint8_t fb; // linear framebuffer mapped
******************************************/
void _start()
{
/*** NOTE: this code runs on all cores in parallel ***/
int x, y, s=bootboot.fb_scanline, w=bootboot.fb_width, h=bootboot.fb_height;
// cross-hair to see screen dimension detected correctly
@ -90,7 +91,7 @@ void puts(char *s)
int x,y,kx=0,line,mask,offs;
int bpl=(font->width+7)/8;
while(*s) {
unsigned char *glyph = (unsigned char*)&_binary_font_psf_start + font->headersize +
unsigned char *glyph = (unsigned char*)&_binary_font_psf_start + font->headersize +
(*s>0&&*s<font->numglyph?*s:0)*font->bytesperglyph;
offs = (kx * (font->width+1) * 4);
for(y=0;y<font->height;y++) {

View file

@ -12,7 +12,7 @@ chainload from MBR, VBR (GPT hybrid booting) or from CDROM boot record via __boo
Machine state
-------------
IRQs masked. GDT unspecified, but valid, IDT unset. Code is running in supervisor mode in ring 0.
IRQs masked. GDT unspecified, but valid, IDT unset. SSE, SMP enabled. Code is running in supervisor mode in ring 0 on all cores.
Installation
------------

View file

@ -1,7 +1,7 @@
;*
;* x86_64-bios/bootboot.asm
;*
;* Copyright (C) 2017 bzt (bztsrc@gitlab)
;* Copyright (C) 2017 - 2019 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
@ -30,7 +30,7 @@
;* 1.0.1 (even expansion ROM), El Torito "no emulation" CDROM boot,
;* as well as Linux boot protocol.
;*
;* memory occupied: 800-7C00
;* text segment occupied: 800-7C00, bss: 8000-x
;*
;* Memory map
;* 0h - 600h reserved for the system
@ -49,7 +49,7 @@
;* 11000h -12000h PDE 2M
;* 12000h -13000h PDE 2M
;* 13000h -14000h PTE 4K
;* 14000h -15000h core stack
;* 14000h -A0000h core stacks (1k per core)
;*
;* At first big enough free hole, initrd. Usually at 1Mbyte.
;*
@ -480,9 +480,7 @@ getmemmap:
mov eax, bootboot_MAGIC
mov dword [bootboot.magic], eax
mov dword [bootboot.size], 128
mov dword [bootboot.pagesize], 12
mov dword [bootboot.protocol_ver], PROTOCOL_STATIC
mov dword [bootboot.loader_type], LOADER_BIOS
mov dword [bootboot.protocol], PROTOCOL_STATIC or LOADER_BIOS
mov di, bootboot.mmap
mov cx, 800h
xor ax, ax
@ -677,8 +675,7 @@ getmemmap:
cmp dword [es:0], '_MP_'
jne .smbnotf
shl eax, 4
mov ebx, dword [es:4]
mov dword [bootboot.mp_ptr], ebx
mov dword [bootboot.mp_ptr], eax
bts dx, 2
jmp .smbnotf
.smbfound: shl eax, 4
@ -732,8 +729,34 @@ getmemmap:
mov cr0, eax
jmp CODE_PROT:protmode_start
;writes the reason, waits for a key and reboots.
;---- enable protmode on APs ----
ap_trampoline:
;--this code will be relocated to the SIPI address --
cli
cld
jmp 0:ap_start
;--relocation end--
ap_start: xor ax, ax
mov ds, ax
lgdt [GDT_value]
mov eax, cr0
or al, 1
mov cr0, eax
jmp CODE_PROT:@f
USE32
@@: mov ax, DATA_PROT
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; spinlock until BSP finishes
@@: pause
cmp byte [bsp_done], 0
jz @b
jmp longmode_init
;writes the reason, waits for a key and reboots.
prot_diefunc:
prot_realmode
USE16
@ -857,7 +880,7 @@ prot_readsectorfunc:
int 13h
jc @f
;some buggy BIOSes (like bochs') fail to set carry flag and ax properly
cmp byte [si+2], 0h
cmp byte [spc_packet+2], 0h
jz @f
;use 2048 byte sectors instead of 512 if it's a cdrom
mov al, byte [lbapacket.sect0]
@ -1712,6 +1735,144 @@ end if
dec cx
jnz .nextfree
.excludeok:
; -------- SMP ---------
; clear LAPIC address and logical core id list
mov edi, lapic_ptr
mov ecx, 512/4+1
xor eax, eax
repnz stosd
; clear flags
mov byte [bsp_done], al
; try ACPI first
mov esi, dword [bootboot.acpi_ptr]
or esi, esi
jz .trymp
mov edx, 4
cmp byte [esi], 'X' ; XSDT has 8 bytes pointers, but we can only access 4G
jne @f
mov edx, 8
@@: mov ecx, dword [esi+4]
add esi, 024h
sub ecx, 024h
.nextsdt: mov ebx, dword [esi]
add esi, edx
cmp dword [ebx], 'APIC' ; look for MADT
je .madt
sub ecx, edx
or ecx, ecx
jz .trymp
jmp .nextsdt
; MADT found.
.madt: mov eax, dword [ebx+24h]
mov dword [lapic_ptr], eax ; madt.lapic_address
mov ecx, dword [ebx+4]
sub ecx, 2ch
add ebx, 2ch
mov edi, lapic_ids
.nextmadtentry:
cmp word [bootboot.numcores], 256
jae .dosmp
cmp byte [ebx], 0 ; madt_entry.type: is it a Local APIC Processor?
jne @f
xor ax, ax
mov al, byte [ebx+2] ; madt_entry.lapicproc.lapicid
stosw ; ACPI table holds 1 byte id, but internally we have 2 bytes
inc word [bootboot.numcores]
@@: xor eax, eax
mov al, byte [ebx+1] ; madt_entry.size
or al, al
jz .dosmp
add ebx, eax
sub ecx, eax
cmp ecx, 0
jg .nextmadtentry
jmp .dosmp
.trymp: ; in lack of ACPI, try legacy MP structures
mov esi, dword [bootboot.mp_ptr]
or esi, esi
jz .nosmp
mov esi, dword [esi+4]
cmp dword [esi], 'PCMP'
jne .nosmp
mov eax, dword [esi+36] ; pcmp.lapic_address
mov dword [lapic_ptr], eax
mov cx, word [esi+34] ; pcmp.numentries
add esi, 44 ; pcmp header length
mov edi, lapic_ids
.nextpcmpentry:
cmp word [bootboot.numcores], 256
jae .dosmp
cmp byte [esi], 0 ; pcmp_entry.type: is it a Local APIC Processor?
jne @f
xor ax, ax
mov al, byte [esi+1] ; pcmp_entry.lapicproc.lapicid
stosw ; PCMP has 1 byte id, but we use 2 bytes internally
inc word [bootboot.numcores]
add esi, 12
@@: add esi, 8
dec cx
jnz .nextpcmpentry
; send IPI and SIPI
.dosmp: cmp word [bootboot.numcores], 2
jb .nosmp
DBG32 dbg_smp
; relocate AP trampoline
mov esi, ap_trampoline
mov edi, 7000h
mov ecx, (ap_start-ap_trampoline+3)/4
repnz movsd
; send Broadcast INIT IPI
mov esi, dword [lapic_ptr]
add esi, 300h
mov eax, 0C4500h
mov dword [esi], eax
; wait 10 millisec
mov al, 10110000b ; select channel 2, lo/hi access, mode 0, binary
out 043h, al
mov ax, 1234DDh/1000*10 ; set counter
out 042h, al
mov al, ah
out 042h, al
@@: mov al, 0C8h ; read back command, channel 2, flush latch, read status
out 043h, al
in al, 042h ; read channel 2 status
bt ax, 7 ; loop until output high bit set
jnc @b
; send Broadcast STARTUP IPI
mov eax, 0C4607h ; start at 0700:0000h
mov dword [esi], eax
; wait 1 millisec (should be 200 microsec minimum)
mov al, 10110000b ; select channel 2, lo/hi access, mode 0, binary
out 043h, al
mov ax, 1234DDh/1000 ; set counter
out 042h, al
mov al, ah
out 042h, al
@@: mov al, 0C8h ; read back command, channel 2, flush latch, read status
out 043h, al
in al, 042h ; read channel 2 status
bt ax, 7 ; loop until output high bit set
jnc @b
mov eax, 0C4607h ; second SIPI
mov dword [esi], eax
.nosmp: ; failsafe
cmp word [bootboot.numcores], 0
jnz @f
inc word [bootboot.numcores]
mov ax, word [bootboot.bspid]
mov word [lapic_ids], ax
@@:
; ------- set video resolution -------
prot_realmode
@ -1836,7 +1997,7 @@ end if
;address 0xffffffffffe00000
xor eax, eax
mov edi, 0A000h
mov ecx, (15000h-0A000h)/4
mov ecx, (14000h+256*1024-0A000h)/4
repnz stosd
;PML4
@ -1875,7 +2036,17 @@ end if
add eax, 4096
dec ecx
jnz @b
mov dword[0DFF8h], 014001h ;map core stack
;map core stacks (one page per 4 cores)
mov edi, 0DFF8h
mov eax, 014001h
mov cx, word [bootboot.numcores]
add cx, 3
shr cx, 2
@@: mov dword[edi], eax
sub edi, 8
add eax, 1000h
dec cx
jnz @b
;identity mapping
;2M PDPE
@ -1937,8 +2108,12 @@ end if
in al, 70h ;disable NMI
or al, 80h
out 70h, al
;release AP spinlock
inc byte [bsp_done]
mov eax, 1101000b ;Set PAE, MCE, PGE
;don't use stack below this line
longmode_init:
mov eax, 1101101000b ;Set PAE, MCE, PGE; OSFXSR, OSXMMEXCPT (enable SSE)
mov cr4, eax
mov eax, 0A000h
mov cr3, eax
@ -1948,15 +2123,15 @@ end if
wrmsr
mov eax, cr0
and al, 0FBh ;clear EM, MP (enable SSE)
or eax, 0C0000001h
mov cr0, eax ;enable paging wich cache disabled
mov cr0, eax ;enable paging with cache disabled
lgdt [GDT_value] ;read 80 bit address
jmp @f
nop
@@: jmp 8:longmode_init
@@: jmp 8:@f
USE64
longmode_init:
xor eax, eax
@@: xor eax, eax ;load long mode segments
mov ax, 10h
mov ds, ax
mov es, ax
@ -1964,8 +2139,27 @@ longmode_init:
mov fs, ax
mov gs, ax
xor rsp, rsp
;call _start() at qword[entrypoint]
; find out our lapic id
mov eax, 1
cpuid
shr ebx, 24
mov edx, ebx
; get array index for it
xor rbx, rbx
mov rsi, lapic_ids
mov cx, word [bootboot.numcores]
@@: lodsw
cmp ax, dx
je @f
inc ebx
dec cx
jnz @b
xor rbx, rbx
@@: shl rbx, 10 ; 1k stack for each core
; set stack and call _start() in sys/core
xor rsp, rsp ;sp = core_num * -1024
sub rsp, rbx
jmp qword[entrypoint]
nop
nop
@ -2322,6 +2516,7 @@ bootdev: db 0
readdev: db 0
hasinitrd: db 0
iscdrom: db 0
bsp_done: ;flag to indicate APs can run
fattype: db 0
bkp: dd ' '
if DEBUG eq 1
@ -2337,6 +2532,7 @@ dbg_gzinitrd db " * Gzip compressed initrd",10,13,0
dbg_scan db " * Autodetecting kernel",10,13,0
dbg_elf db " * Parsing ELF64",10,13,0
dbg_pe db " * Parsing PE32+",10,13,0
dbg_smp db " * SMP init",10,13,0
dbg_vesa db " * Screen VESA VBE",10,13,0
end if
backup: db " * Backup initrd",10,13,0
@ -2383,6 +2579,8 @@ core_len: dd ?
gpt_ptr: dd ?
gpt_num: dd ?
gpt_ent: dd ?
lapic_ptr: dd ?
lapic_ids:
tinf_bss_start:
d_end: dd ?
d_lzOff: dd ?

View file

@ -1,7 +1,7 @@
;*
;* x86_64-bios/bootboot.inc
;*
;* Copyright (C) 2017 bzt (bztsrc@gitlab)
;* Copyright (C) 2017 - 2019 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
@ -47,12 +47,12 @@ PROTOCOL_STATIC equ 1
; kernel name parsed from environment, kernel memory addresses parsed from ELF symbols
PROTOCOL_DYNAMIC equ 2
; big-endian flag
PROTOCOL_BIGENDIAN equ 080h
PROTOCOL_BIGENDIAN equ 080h
; loader types, just informational
LOADER_BIOS equ 0
LOADER_UEFI equ 1
LOADER_RPI equ 2
LOADER_BIOS equ 0
LOADER_UEFI equ 4
LOADER_RPI equ 8
; framebuffer pixel format, only 32 bits supported
FB_ARGB equ 0
@ -81,31 +81,26 @@ MMAP_MMIO equ 4
INITRD_MAXSIZE equ 16 ; Mb
virtual at bootboot
; first 64 bytes is platform independent
bootboot.magic: dd 0
bootboot.size: dd 0
bootboot.protocol_ver:db 1
bootboot.loader_type: db 0
bootboot.pagesize: db 0
bootboot.protocol: db 1
bootboot.fb_type: db 0
bootboot.numcores: dw 0
bootboot.bspid: dw 0
bootboot.timezone: dw 0
bootboot.datetime: dq 0
bootboot.initrd_ptr: dq 0
bootboot.initrd_size: dq 0
bootboot.fb_ptr: dq 0
bootboot.fb_size: dd 0
bootboot.fb_width: dd 0
bootboot.fb_height: dd 0
bootboot.fb_scanline: dd 0
; architecture specific pointers
; the rest (64 bytes) is platform specific
; x86_64
bootboot.acpi_ptr: dq 0
bootboot.smbi_ptr: dq 0
bootboot.efi_ptr: dq 0
@ -119,3 +114,5 @@ end virtual

View file

@ -9,7 +9,7 @@ OS loader application.
Machine state
-------------
IRQs masked. GDT unspecified, but valid, IDT unset. Code is running in supervisor mode in ring 0.
IRQs masked. GDT unspecified, but valid, IDT unset. SSE, SMP enabled. Code is running in supervisor mode in ring 0 on all cores.
File system drivers
-------------------

View file

@ -1,7 +1,7 @@
/*
* x86_64-efi/bootboot.c
*
* Copyright (C) 2017 bzt (bztsrc@gitlab)
* Copyright (C) 2017 - 2019 bzt (bztsrc@gitlab)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@ -123,11 +123,72 @@ typedef struct {
} pe_hdr;
/*** EFI defines and structs ***/
extern EFI_GUID GraphicsOutputProtocol;
extern EFI_GUID LoadedImageProtocol;
struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
struct EFI_FILE_PROTOCOL;
#ifndef EFI_MP_SERVICES_PROTOCOL_GUID
#define EFI_MP_SERVICES_PROTOCOL_GUID \
{ 0x3fdda605, 0xa76e, 0x4f46, {0xad, 0x29, 0x12, 0xf4, 0x53, 0x1b, 0x3d, 0x08} }
typedef struct _EFI_MP_SERVICES_PROTOCOL EFI_MP_SERVICES_PROTOCOL;
#define PROCESSOR_AS_BSP_BIT 0x00000001
typedef struct {
UINT64 ProcessorId;
UINT32 StatusFlag;
} EFI_PROCESSOR_INFORMATION;
typedef
EFI_STATUS
(EFIAPI *EFI_MP_SERVICES_DUMMY)(
IN EFI_MP_SERVICES_PROTOCOL *This
);
typedef
VOID
(EFIAPI *EFI_AP_PROCEDURE)(
IN OUT VOID *Buffer
);
typedef
EFI_STATUS
(EFIAPI *EFI_MP_SERVICES_GET_NUMBER_OF_PROCESSORS)(
IN EFI_MP_SERVICES_PROTOCOL *This,
OUT UINTN *NumberOfProcessors,
OUT UINTN *NumberOfEnabledProcessors
);
typedef
EFI_STATUS
(EFIAPI *EFI_MP_SERVICES_GET_PROCESSOR_INFO)(
IN EFI_MP_SERVICES_PROTOCOL *This,
IN UINTN ProcessorNumber,
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
);
typedef
EFI_STATUS
(EFIAPI *EFI_MP_SERVICES_STARTUP_THIS_AP)(
IN EFI_MP_SERVICES_PROTOCOL *This,
IN EFI_AP_PROCEDURE Procedure,
IN UINTN ProcessorNumber,
IN EFI_EVENT WaitEvent OPTIONAL,
IN UINTN TimeoutInMicroseconds,
IN VOID *ProcedureArgument OPTIONAL,
OUT BOOLEAN *Finished OPTIONAL
);
struct _EFI_MP_SERVICES_PROTOCOL {
EFI_MP_SERVICES_GET_NUMBER_OF_PROCESSORS GetNumberOfProcessors;
EFI_MP_SERVICES_GET_PROCESSOR_INFO GetProcessorInfo;
EFI_MP_SERVICES_DUMMY StartupAllAPs;
EFI_MP_SERVICES_STARTUP_THIS_AP StartupThisAP;
EFI_MP_SERVICES_DUMMY SwitchBSP;
EFI_MP_SERVICES_DUMMY EnableDisableAP;
EFI_MP_SERVICES_DUMMY WhoAmI;
};
#endif
typedef
EFI_STATUS
(EFIAPI *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME)(
@ -211,7 +272,7 @@ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
EFI_FILE_HANDLE RootDir;
EFI_FILE_PROTOCOL *Root;
SIMPLE_INPUT_INTERFACE *CI;
unsigned char *kne;
unsigned char *kne, bsp_done=0;
// default environment variables. M$ states that 1024x768 must be supported
int reqwidth = 1024, reqheight = 768;
@ -1130,6 +1191,46 @@ LoadCore()
return report(EFI_LOAD_ERROR,L"Kernel not found in initrd");
}
/**
* Initialize logical cores
* Because Local APIC ID is not contiguous, core id != core num
*/
VOID EFIAPI bootboot_startcore(IN VOID* buf)
{
// we have a scalar number, not a pointer, so cast it
UINTN core_num = (UINTN)buf;
// spinlock until BSP finishes
do { __asm__ __volatile__ ("pause"); } while(!bsp_done);
// enable SSE
__asm__ __volatile__ (
"mov %%cr0, %%eax;"
"btsw $2, %%ax;"
"btrw $1, %%ax;"
"mov %%rax, %%cr0;"
"mov %%cr4, %%rax;"
"orw $3 << 9, %%ax;"
"mov %%rax, %%cr4"
: );
// set up paging
__asm__ __volatile__ (
"mov %0, %%rax;"
"mov %%rax, %%cr3"
: : "b"(paging) : "memory" );
// set stack and call _start() in sys/core
__asm__ __volatile__ (
// get a valid stack for the core we're running on
"xorq %%rsp, %%rsp;"
"subq %1, %%rsp;" // sp = core_num * -1024
// pass control over
"pushq %0;"
"retq"
: : "a"(entrypoint), "r"(core_num*1024) : "memory" );
}
/**
* Main EFI application entry point
*/
@ -1148,7 +1249,12 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
EFI_PARTITION_TABLE_HEADER *gptHdr;
EFI_PARTITION_ENTRY *gptEnt;
EFI_INPUT_KEY key;
UINTN i, j=0, handle_size=0,memory_map_size=0, map_key=0, desc_size=0;
EFI_EVENT Event;
EFI_GUID mpspGuid = EFI_MP_SERVICES_PROTOCOL_GUID;
EFI_MP_SERVICES_PROTOCOL *mp;
UINT8 pibuffer[100];
EFI_PROCESSOR_INFORMATION *pibuf=(EFI_PROCESSOR_INFORMATION*)pibuffer;
UINTN bsp_num=0, i, j=0, handle_size=0,memory_map_size=0, map_key=0, desc_size=0;
UINT32 desc_version=0;
UINT64 lba_s=0,lba_e=0;
MMapEnt *mmapent, *last=NULL;
@ -1435,10 +1541,9 @@ gzerr: return report(EFI_COMPROMISED_DATA,L"Unable to uncompress");
return report(status, L"GOP failed, no framebuffer");
// collect information on system
bootboot->protocol=PROTOCOL_STATIC;
bootboot->loader_type=LOADER_UEFI;
bootboot->protocol=PROTOCOL_STATIC | LOADER_UEFI;
bootboot->size=128;
bootboot->pagesize=12;
bootboot->numcores=1;
CopyMem((void *)&(bootboot->initrd_ptr),&initrd.ptr,8);
bootboot->initrd_size=((initrd.size+PAGESIZE-1)/PAGESIZE)*PAGESIZE;
CopyMem((void *)&(bootboot->x86_64.efi_ptr),&systab,8);
@ -1492,6 +1597,34 @@ gzerr: return report(EFI_COMPROMISED_DATA,L"Unable to uncompress");
if(kne!=NULL)
*kne='\n';
// Symmetric Multi Processing support
status = uefi_call_wrapper(BS->LocateProtocol, 3, &mpspGuid, NULL, (void**)&mp);
if(!EFI_ERROR(status)) {
// override default values in bootboot struct
status = uefi_call_wrapper(mp->GetNumberOfProcessors, 3, mp, &i, &j);
if(!EFI_ERROR(status)) {
// failsafe: we cannot map more stacks (each core has 1k)
if(i>PAGESIZE/8/2*4) i=PAGESIZE/8/2*4;
bootboot->numcores = i;
}
DBG(L" * SMP numcores %d\n", bootboot->numcores);
// start APs
status = uefi_call_wrapper(BS->CreateEvent, 5, 0, TPL_NOTIFY, NULL, NULL, &Event);
if(!EFI_ERROR(status)) {
for(i=0; i<bootboot->numcores; i++) {
status = uefi_call_wrapper(mp->GetProcessorInfo, 5, mp, i, pibuf);
if(!EFI_ERROR(status)) {
if(pibuf->StatusFlag & PROCESSOR_AS_BSP_BIT) {
bootboot->bspid = pibuf->ProcessorId;
bsp_num = i;
} else {
uefi_call_wrapper(mp->StartupThisAP, 7, mp, bootboot_startcore, i, Event, 0, (VOID*)i, NULL);
}
}
}
}
}
// query size of memory map
status = uefi_call_wrapper(BS->GetMemoryMap, 5,
&memory_map_size, memory_map, NULL, &desc_size, NULL);
@ -1509,7 +1642,7 @@ gzerr: return report(EFI_COMPROMISED_DATA,L"Unable to uncompress");
}
// create page tables
uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, 24, (EFI_PHYSICAL_ADDRESS*)&paging);
uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, 23+(bootboot->numcores+3)/4, (EFI_PHYSICAL_ADDRESS*)&paging);
if (paging == NULL) {
return report(EFI_OUT_OF_RESOURCES,L"AllocatePages");
}
@ -1529,7 +1662,8 @@ gzerr: return report(EFI_COMPROMISED_DATA,L"Unable to uncompress");
paging[3*512+1]=(UINT64)(env.ptr)+1;
for(i=0;i<(core.size/PAGESIZE);i++)
paging[3*512+2+i]=(UINT64)((UINT8 *)core.ptr+i*PAGESIZE+1);
paging[3*512+511]=(UINT64)((UINT8 *)paging+23*PAGESIZE+1); // core stack
for(i=0; i<(UINTN)((bootboot->numcores+3)/4); i++)
paging[3*512+511-i]=(UINT64)((UINT8 *)paging+(23+i)*PAGESIZE+1); // core stacks
//identity mapping
//2M PDPE
for(i=0;i<16;i++)
@ -1604,18 +1738,9 @@ get_memory_map:
return report(status,L"ExitBootServices");
}
//set up paging
__asm__ __volatile__ (
"mov %0,%%rax;"
"mov %%rax,%%cr3"
: : "b"(paging) : "memory" );
//call _start() in sys/core
__asm__ __volatile__ (
"xorq %%rsp, %%rsp;"
"pushq %0;"
"retq"
: : "a"(entrypoint): "memory" );
// release AP spinlock
bsp_done = 1;
bootboot_startcore((VOID*)bsp_num);
}
return report(status,L"Initrd not found");
}