[haiku-commits] BRANCH jessicah-github.efi.master [e3db0d1c7983] src/system/boot/platform/efi

  • From: jessicah-github.efi.master <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 3 May 2015 01:01:44 +0200 (CEST)

added 6 changesets to branch 'refs/remotes/jessicah-github/efi.master'
old head: d026b9601a9614a69743bbd93e2da75b721f4d03
new head: e3db0d1c79831a32b117eac4a0952df4fcb9ca3d
overview: https://github.com/jessicah/haiku/compare/d026b9601a96...e3db0d1c7983

----------------------------------------------------------------------------

660876b94770: First stab at SMP

[ Nick Smallbone <nick.smallbone@xxxxxxxxx> ]

631b0bc38f4d: Making progress with SMP bring-up

[ Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> ]

e1a1cb7e936c: More SMP work...

[ Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> ]

a88a807aafdd: Fix bug setting smp_trampoline_args.

[ Nick Smallbone <nick.smallbone@xxxxxxxxx> ]

f3333f1435cd: Fix several silly bugs in trampoline

[ Nick Smallbone <nick.smallbone@xxxxxxxxx> ]

e3db0d1c7983: Fix up SMP, add some extra debugging for testing on actual
hardware.

[ Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx> ]

----------------------------------------------------------------------------

11 files changed, 352 insertions(+), 103 deletions(-)
src/system/boot/platform/efi/Jamfile | 1 +
src/system/boot/platform/efi/cpu.cpp | 25 ++-
src/system/boot/platform/efi/debug.cpp | 2 +-
src/system/boot/platform/efi/entry.S | 4 +-
src/system/boot/platform/efi/serial.cpp | 57 ++++++-
src/system/boot/platform/efi/serial.h | 2 +
src/system/boot/platform/efi/smp.cpp | 199 ++++++++++++++--------
src/system/boot/platform/efi/smp.h | 2 +-
src/system/boot/platform/efi/smp_trampoline.S | 129 ++++++++++++++
src/system/boot/platform/efi/start.cpp | 13 +-
src/system/boot/platform/efi/support.S | 21 ---

############################################################################

Commit: 660876b94770e60e873f42d878d26baa9bb910a4
Author: Nick Smallbone <nick.smallbone@xxxxxxxxx>
Date: Sat May 2 19:43:33 2015 UTC
Committer: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Sat May 2 19:59:19 2015 UTC

First stab at SMP

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/Jamfile
b/src/system/boot/platform/efi/Jamfile
index 05ee068..9d4b8ef 100644
--- a/src/system/boot/platform/efi/Jamfile
+++ b/src/system/boot/platform/efi/Jamfile
@@ -9,7 +9,7 @@ UsePrivateHeaders [ FDirName kernel boot platform efi arch
$(TARGET_ARCH) ] ;
local defines = _BOOT_MODE GNU_EFI_USE_MS_ABI _BOOT_PLATFORM_efi ;
defines = [ FDefines $(defines) ] ;
SubDirCcFlags $(defines) ;
- SubDirC++Flags $(defines) -fno-rtti ;
+ SubDirC++Flags $(defines) -fno-rtti -std=gnu++11 ;
}

local efi_glue_src =
@@ -35,6 +35,7 @@ BootMergeObject boot_platform_efi.o :
hpet.cpp
cpu.cpp
smp.cpp
+ smp_trampoline.S
support.S
$(efi_glue_src)
:
diff --git a/src/system/boot/platform/efi/smp.cpp
b/src/system/boot/platform/efi/smp.cpp
index ccd7216..c6be1ee 100644
--- a/src/system/boot/platform/efi/smp.cpp
+++ b/src/system/boot/platform/efi/smp.cpp
@@ -16,6 +16,7 @@

#include <kernel.h>
#include <safemode.h>
+#include <boot/platform.h>
#include <boot/stage2.h>
#include <boot/menu.h>
#include <arch/x86/apic.h>
@@ -42,8 +43,32 @@
extern "C" void execute_n_instructions(int count);

extern "C" void smp_trampoline(void);
+extern "C" void smp_trampoline_args(void);
extern "C" void smp_trampoline_end(void);

+struct gdtr {
+ uint16 limit;
+ uint32 base;
+ unsigned char null[8];
+ unsigned char code[8];
+ unsigned char data[8];
+} __attribute__((packed));
+
+// Arguments passed to the SMP trampoline.
+struct trampoline_args {
+ uint32 trampoline; // Trampoline address
+ uint32 gdt32; // 32-bit GDTR
+ uint32 pml4; // 64-bit PML4
+ uint32 gdt64; // 64-bit GDTR
+ uint64 kernel_entry; // Kernel entry point
+ uint64 kernel_args; // Kernel arguments
+ uint64 current_cpu; // CPU number
+ uint64 stack_top; // Kernel stack
+ volatile uint64 sentinel; // Sentinel, AP sets to 0 when finished
+
+ // smp_boot_other_cpus puts the GDTR here.
+ struct gdtr gdtr;
+};

static uint32
apic_read(uint32 offset)
@@ -217,21 +242,21 @@ smp_init_other_cpus(void)
if (gKernelArgs.num_cpus < 2)
return;

-#if false
for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) {
// create a final stack the trampoline code will put the ap
processor on
- gKernelArgs.cpu_kstack[i].start = (addr_t)mmu_allocate(NULL,
- KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES *
B_PAGE_SIZE);
- gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE
- + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
+ void * stack = NULL;
+ const size_t size = KERNEL_STACK_SIZE +
KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
+ if (platform_allocate_region(&stack, size, 0, false) != B_OK) {
+ panic("Unable to allocate AP stack");
+ }
+ memset(stack, 0, size);
+ gKernelArgs.cpu_kstack[i].start = (uint64)stack;
+ gKernelArgs.cpu_kstack[i].size = size;
}
-#endif
}

-
-#if false
void
-smp_boot_other_cpus(void (*entryFunc)(void))
+smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64 kernel_entry)
{
if (gKernelArgs.num_cpus < 2)
return;
@@ -245,55 +270,41 @@ smp_boot_other_cpus(void (*entryFunc)(void))
// (these have to be < 1M physical, 0xa0000-0xfffff is reserved by the
BIOS,
// and when PXE services are used, the 0x8d000-0x9ffff is also reserved)
#ifdef _PXE_ENV
- uint32 trampolineCode = 0x8b000;
- uint32 trampolineStack = 0x8c000;
+ uint64 trampolineCode = 0x8b000;
+ uint64 trampolineStack = 0x8c000;
#else
- uint32 trampolineCode = 0x9f000;
- uint32 trampolineStack = 0x9e000;
+ uint64 trampolineCode = 0x9f000;
+ uint64 trampolineStack = 0x9e000;
#endif

// copy the trampoline code over
memcpy((char *)trampolineCode, (const void*)&smp_trampoline,
- (uint32)&smp_trampoline_end - (uint32)&smp_trampoline);
+ (uint64)&smp_trampoline_end - (uint64)&smp_trampoline);

// boot the cpus
for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) {
- uint32 *finalStack;
- uint32 *tempStack;
uint32 config;
- uint32 numStartups;
+ uint64 numStartups;
uint32 j;
-
- // set this stack up
- finalStack = (uint32 *)gKernelArgs.cpu_kstack[i].start;
- memset((uint8*)finalStack + KERNEL_STACK_GUARD_PAGES *
B_PAGE_SIZE, 0,
- KERNEL_STACK_SIZE);
- tempStack = (finalStack
- + (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES *
B_PAGE_SIZE)
- / sizeof(uint32)) - 1;
- *tempStack = (uint32)entryFunc;
-
- // set the trampoline stack up
- tempStack = (uint32 *)(trampolineStack + B_PAGE_SIZE - 4);
- // final location of the stack
- *tempStack = ((uint32)finalStack) + KERNEL_STACK_SIZE
- + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE -
sizeof(uint32);
- tempStack--;
- // page dir
- *tempStack = x86_read_cr3() & 0xfffff000;
-
- // put a gdt descriptor at the bottom of the stack
- *((uint16 *)trampolineStack) = 0x18 - 1; // LIMIT
- *((uint32 *)(trampolineStack + 2)) = trampolineStack + 8;
-
- // construct a temporary gdt at the bottom
- segment_descriptor* tempGDT
- = (segment_descriptor*)&((uint32 *)trampolineStack)[2];
- clear_segment_descriptor(&tempGDT[0]);
- set_segment_descriptor(&tempGDT[1], 0, 0xffffffff,
DT_CODE_READABLE,
- DPL_KERNEL);
- set_segment_descriptor(&tempGDT[2], 0, 0xffffffff,
DT_DATA_WRITEABLE,
- DPL_KERNEL);
+ trampoline_args * args = (trampoline_args *)trampolineStack;
+ args->trampoline = trampolineCode;
+ args->gdt32 = (uint64) &args->gdtr;
+ args->gdtr = {23, (uint32)(uint64)args->gdtr.null,
+ {0, 0, 0, 0, 0, 0, 0, 0},
+ {0xff, 0xff, 0, 0, 0, 0x9a, 0xcf, 0},
+ {0xff, 0xff, 0, 0, 0, 0x92, 0xcf, 0}};
+ args->pml4 = pml4;
+ args->gdt64 = gdt64;
+ args->kernel_entry = kernel_entry;
+ args->kernel_args = (uint64)&gKernelArgs;
+ args->current_cpu = i;
+ args->stack_top = gKernelArgs.cpu_kstack[i].start +
gKernelArgs.cpu_kstack[i].size;
+ args->sentinel = 1;
+
+ // put the args in the right place
+ trampoline_args ** args_ptr =
+ (trampoline_args **)(trampolineStack +
(uint64)smp_trampoline_args - (uint64)smp_trampoline);
+ *args_ptr = args;

/* clear apic errors */
if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {
@@ -363,14 +374,12 @@ dprintf("wait for delivery\n");
// Wait for the trampoline code to clear the final stack
location.
// This serves as a notification for us that it has loaded the
address
// and it is safe for us to overwrite it to trampoline the next
CPU.
- tempStack++;
- while (*tempStack != 0)
+ while (args->sentinel != 0)
spin(1000);
}

TRACE(("done trampolining\n"));
}
-#endif


void
diff --git a/src/system/boot/platform/efi/smp.h
b/src/system/boot/platform/efi/smp.h
index 4acda16..b2eda62 100644
--- a/src/system/boot/platform/efi/smp.h
+++ b/src/system/boot/platform/efi/smp.h
@@ -19,7 +19,7 @@ extern "C" {

extern void smp_init(void);
extern void smp_init_other_cpus(void);
-extern void smp_boot_other_cpus(void (*entryFunc)(void));
+extern void smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64
kernel_entry);

extern int smp_get_current_cpu(void);

diff --git a/src/system/boot/platform/efi/smp_trampoline.S
b/src/system/boot/platform/efi/smp_trampoline.S
new file mode 100644
index 0000000..69800f1
--- /dev/null
+++ b/src/system/boot/platform/efi/smp_trampoline.S
@@ -0,0 +1,126 @@
+/*
+** Copyright 2001, Travis Geiselbrecht. All rights reserved.
+** Copyright 2012, Alex Smith, alex@xxxxxxxxxxxxxxxx.
+** Distributed under the terms of the NewOS License.
+*/
+
+// Relocatable. Before calling, smp_trampoline_args should point
+// to a struct trampoline_args (see smp.cpp). This pointer should
+// be 16-byte aligned, below 1MB and identity-mapped.
+.globl smp_trampoline
+.globl smp_trampoline_end
+.globl smp_trampoline_args
+
+#include <asm_defs.h>
+
+#include <arch/x86/descriptors.h>
+#include "mmu.h"
+
+.code16
+smp_trampoline:
+ cli
+
+// movl 0xdeadbeef, esi
+ .byte 0x66
+ .byte 0xbe
+smp_trampoline_args:
+ .long 0xdeadbeef
+
+ // Load the trampoline args into ss.
+ movl %esi, %eax
+ shrl $4, %eax
+ movw %ax, %ss
+ xorw %sp, %sp
+
+ // Switch to protected mode.
+ popl %ebx
+ popl %edx
+ lgdt (%edx)
+
+ movl %cr0,%eax
+ orl $0x01,%eax
+ movl %eax,%cr0
+
+ pushl $8
+ pushl (trampoline_32 - smp_trampoline)(%ebx)
+ .byte 0x66
+.code32
+ retf
+
+trampoline_32:
+ mov $0x10, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+ // Put the trampoline args on the stack.
+ movl %esi, %esp
+ addl $8, %esp
+
+ // Enable PAE and PGE
+ movl %cr4, %eax
+ orl $(1 << 5) | (1 << 7), %eax
+ movl %eax, %cr4
+
+ // Point CR3 to the kernel's PML4.
+ popl %eax
+ movl %eax, %cr3
+
+ // Enable long mode by setting EFER.LME.
+ movl $0xc0000080, %ecx
+ rdmsr
+ orl $(1 << 8), %eax
+ wrmsr
+
+ // Re-enable paging, which will put us in compatibility mode as we are
+ // currently in a 32-bit code segment.
+ movl %cr0, %ecx
+ orl $(1 << 31), %ecx
+ movl %ecx, %cr0
+
+ // Load 64-bit enabled GDT
+ popl %eax
+ lgdtl (%eax)
+
+ // Jump into the 64-bit code segment.
+ pushl $KERNEL_CODE_SELECTOR
+ pushl (.Llmode - smp_trampoline)(%ebx)
+ retf
+.align 8
+.code64
+.Llmode:
+ // Set data segments.
+ mov $KERNEL_DATA_SELECTOR, %ax
+ mov %ax, %ss
+ xor %ax, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+
+ // Initialisation that comes from long_smp_start_kernel.
+ movq %cr0, %rax
+ orq $0x10000, %rax
+ andq $(~6), %rax
+ movq %rax, %cr0
+ fninit
+ movq %cr4, %rax
+ orq $0x600, %rax
+ movq %rax, %cr4
+
+ // Get kernel arguments.
+ popq %rax
+ popq %rdi
+ popq %rsi
+
+ // Set the stack pointer, write to the sentinel and clear the stack
frame/RFLAGS.
+ popq %rbp
+ movq $0, (%rsp)
+ movq %rbp, %rsp
+ xorq %rbp, %rbp
+ push $0
+ popf
+
+ // Call the entry point.
+ call *%rax
diff --git a/src/system/boot/platform/efi/start.cpp
b/src/system/boot/platform/efi/start.cpp
index 033c6bc..8fcf0d3 100644
--- a/src/system/boot/platform/efi/start.cpp
+++ b/src/system/boot/platform/efi/start.cpp
@@ -267,7 +267,7 @@ platform_start_kernel(void)
// Update EFI, generate final kernel physical memory map, etc.
mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size,
descriptor_version);

- //smp_boot_other_cpus(long_smp_start_kernel);
+ smp_boot_other_cpus(final_pml4, gLongGDT, gLongKernelEntry);

// Enter the kernel!
efi_enter_kernel(final_pml4,

############################################################################

Commit: 631b0bc38f4ddbd2ab87ab672592df0db8b02550
Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date: Sat May 2 20:41:45 2015 UTC

Making progress with SMP bring-up

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/Jamfile
b/src/system/boot/platform/efi/Jamfile
index 9d4b8ef..4033224 100644
--- a/src/system/boot/platform/efi/Jamfile
+++ b/src/system/boot/platform/efi/Jamfile
@@ -9,7 +9,7 @@ UsePrivateHeaders [ FDirName kernel boot platform efi arch
$(TARGET_ARCH) ] ;
local defines = _BOOT_MODE GNU_EFI_USE_MS_ABI _BOOT_PLATFORM_efi ;
defines = [ FDefines $(defines) ] ;
SubDirCcFlags $(defines) ;
- SubDirC++Flags $(defines) -fno-rtti -std=gnu++11 ;
+ SubDirC++Flags $(defines) -fno-rtti ;
}

local efi_glue_src =
diff --git a/src/system/boot/platform/efi/serial.cpp
b/src/system/boot/platform/efi/serial.cpp
index 7f30711..f126241 100644
--- a/src/system/boot/platform/efi/serial.cpp
+++ b/src/system/boot/platform/efi/serial.cpp
@@ -24,6 +24,22 @@ static const uint32 kSerialBaudRate = 115200;

static SERIAL_IO_INTERFACE *sSerial = NULL;
static int32 sSerialEnabled = 0;
+static bool sSerialUsesEFI = true;
+
+
+enum serial_register_offsets {
+ SERIAL_TRANSMIT_BUFFER = 0,
+ SERIAL_RECEIVE_BUFFER = 0,
+ SERIAL_DIVISOR_LATCH_LOW = 0,
+ SERIAL_DIVISOR_LATCH_HIGH = 1,
+ SERIAL_FIFO_CONTROL = 2,
+ SERIAL_LINE_CONTROL = 3,
+ SERIAL_MODEM_CONTROL = 4,
+ SERIAL_LINE_STATUS = 5,
+ SERIAL_MODEM_STATUS = 6,
+};
+
+static uint16 sSerialBasePort = 0x3f8;


static void
@@ -32,14 +48,21 @@ serial_putc(char c)
UINTN bufSize = 1;
/* The only real EFI example I've seen (grub) doesn't check if it is ok
to
send so I assuem we don't need to check. Seems to work. */
- sSerial->Write(sSerial, &bufSize, &c);
+ if (sSerialUsesEFI) {
+ sSerial->Write(sSerial, &bufSize, &c);
+ } else {
+ while ((in8(sSerialBasePort + SERIAL_LINE_STATUS) & 0x20) == 0)
+ asm volatile ("pause;");
+
+ out8(c, sSerialBasePort + SERIAL_TRANSMIT_BUFFER);
+ }
}


extern "C" void
serial_puts(const char* string, size_t size)
{
- if (sSerialEnabled <= 0 || sSerial == NULL)
+ if (sSerialEnabled <= 0 || (sSerial == NULL && sSerialUsesEFI))
return;

//TODO: We can write strings instead of char by char.
@@ -114,3 +137,33 @@ serial_init(void)
serial_enable();
#endif
}
+
+
+extern "C" void
+serial_switch_to_bios(void)
+{
+ // we can't use this once we exit UEFI
+ sSerial = NULL;
+ sSerialUsesEFI = false;
+
+ // copy the base ports of the optional 4 serial ports to the kernel args
+ // 0x0000:0x0400 is the location of that information in the BIOS data
+ // segment
+ uint16_t* ports = (uint16_t*)0x400;
+ memcpy(gKernelArgs.platform_args.serial_base_ports, ports,
+ sizeof(uint16) * MAX_SERIAL_PORTS);
+
+ // only use the port if we could find one, else use the standard port
+ if (gKernelArgs.platform_args.serial_base_ports[0] != 0)
+ sSerialBasePort =
gKernelArgs.platform_args.serial_base_ports[0];
+
+ uint16 divisor = uint16(115200 / kSerialBaudRate);
+
+ out8(0x80, sSerialBasePort + SERIAL_LINE_CONTROL);
+ // set divisor latch access bit
+ out8(divisor & 0xf, sSerialBasePort + SERIAL_DIVISOR_LATCH_LOW);
+ out8(divisor >> 8, sSerialBasePort + SERIAL_DIVISOR_LATCH_HIGH);
+ out8(3, sSerialBasePort + SERIAL_LINE_CONTROL);
+ // 8N1
+}
+
diff --git a/src/system/boot/platform/efi/serial.h
b/src/system/boot/platform/efi/serial.h
index 03c5647..ee2bf2a 100644
--- a/src/system/boot/platform/efi/serial.h
+++ b/src/system/boot/platform/efi/serial.h
@@ -22,6 +22,8 @@ extern void serial_puts(const char *string, size_t size);
extern void serial_disable(void);
extern void serial_enable(void);

+extern void serial_switch_to_bios(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/system/boot/platform/efi/smp.cpp
b/src/system/boot/platform/efi/smp.cpp
index c6be1ee..b4c9e40 100644
--- a/src/system/boot/platform/efi/smp.cpp
+++ b/src/system/boot/platform/efi/smp.cpp
@@ -278,11 +278,15 @@ smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64
kernel_entry)
#endif

// copy the trampoline code over
+ TRACE(("copying the trampoline code to %p from %p\n",
(char*)trampolineCode, (const void*)&smp_trampoline));
+ TRACE(("size of trampoline code = %d bytes\n",
(uint64)&smp_trampoline_end - (uint64)&smp_trampoline));
memcpy((char *)trampolineCode, (const void*)&smp_trampoline,
(uint64)&smp_trampoline_end - (uint64)&smp_trampoline);

// boot the cpus
+ TRACE(("we have %d CPUs to boot...\n", gKernelArgs.num_cpus - 1));
for (uint32 i = 1; i < gKernelArgs.num_cpus; i++) {
+ TRACE(("trampolining CPU %d\n", i));
uint32 config;
uint64 numStartups;
uint32 j;
diff --git a/src/system/boot/platform/efi/smp_trampoline.S
b/src/system/boot/platform/efi/smp_trampoline.S
index 69800f1..3607f20 100644
--- a/src/system/boot/platform/efi/smp_trampoline.S
+++ b/src/system/boot/platform/efi/smp_trampoline.S
@@ -1,4 +1,4 @@
-/*
+/*
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
** Copyright 2012, Alex Smith, alex@xxxxxxxxxxxxxxxx.
** Distributed under the terms of the NewOS License.
@@ -86,7 +86,7 @@ trampoline_32:
// Jump into the 64-bit code segment.
pushl $KERNEL_CODE_SELECTOR
pushl (.Llmode - smp_trampoline)(%ebx)
- retf
+ retf
.align 8
.code64
.Llmode:
@@ -124,3 +124,4 @@ trampoline_32:

// Call the entry point.
call *%rax
+smp_trampoline_end:
diff --git a/src/system/boot/platform/efi/start.cpp
b/src/system/boot/platform/efi/start.cpp
index 8fcf0d3..7175423 100644
--- a/src/system/boot/platform/efi/start.cpp
+++ b/src/system/boot/platform/efi/start.cpp
@@ -264,6 +264,10 @@ platform_start_kernel(void)
// The console was provided by boot services, disable it.
stdout = NULL;

+ // Switch to BIOS serial output
+ serial_switch_to_bios();
+ dprintf("can we still serial debug?\n");
+
// Update EFI, generate final kernel physical memory map, etc.
mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size,
descriptor_version);


############################################################################

Commit: e1a1cb7e936c3f3f4c959c5c2831cc491b978f18
Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date: Sat May 2 21:55:30 2015 UTC

More SMP work...

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/cpu.cpp
b/src/system/boot/platform/efi/cpu.cpp
index 7e75f39..fb88ee9 100644
--- a/src/system/boot/platform/efi/cpu.cpp
+++ b/src/system/boot/platform/efi/cpu.cpp
@@ -24,7 +24,7 @@
#include <string.h>


-//#define TRACE_CPU
+#define TRACE_CPU
#ifdef TRACE_CPU
# define TRACE(x) dprintf x
#else
@@ -297,7 +297,7 @@ slower_sample:

gKernelArgs.arch_args.system_time_cv_factor = gTimeConversionFactor;
gKernelArgs.arch_args.cpu_clock_speed = clockSpeed;
- //dprintf("factors: %lu %llu\n", gTimeConversionFactor, clockSpeed);
+ dprintf("factors: %lu %llu\n", gTimeConversionFactor, clockSpeed);

if (quickSampleCount > 1) {
dprintf("needed %" B_PRIu32 " quick samples for TSC
calibration\n",
@@ -320,6 +320,27 @@ slower_sample:
// #pragma mark -


+#if false
+extern "C" bigtime_t
+system_time()
+{
+ bigtime_t timestamp = rdtsc();
+ timestamp *= gTimeConversionFactor;
+ timestamp /= 4294967296;
+ return timestamp;
+
+}
+#else
+extern "C" bigtime_t
+system_time()
+{
+ uint64 lo, hi;
+ asm("rdtsc": "=a"(lo), "=d"(hi));
+ return ((lo * gTimeConversionFactor) >> 32) + hi *
gTimeConversionFactor;
+}
+#endif
+
+
extern "C" void
spin(bigtime_t microseconds)
{
diff --git a/src/system/boot/platform/efi/smp.cpp
b/src/system/boot/platform/efi/smp.cpp
index b4c9e40..0f5a3dd 100644
--- a/src/system/boot/platform/efi/smp.cpp
+++ b/src/system/boot/platform/efi/smp.cpp
@@ -84,6 +84,20 @@ apic_write(uint32 offset, uint32 data)
}


+static uint32
+apic_read_phys(uint32 offset)
+{
+ return *(volatile uint32 *)((addr_t)(void
*)gKernelArgs.arch_args.apic_phys + offset);
+}
+
+
+static void
+apic_write_phys(uint32 offset, uint32 data)
+{
+ *(volatile uint32 *)((addr_t)(void *)gKernelArgs.arch_args.apic_phys +
offset) = data;
+}
+
+
static status_t
smp_do_acpi_config(void)
{
@@ -190,6 +204,29 @@ calculate_apic_timer_conversion_factor(void)
// #pragma mark -


+extern "C" status_t
+platform_bootloader_address_to_kernel_address(void *address, uint64_t
*_result);
+
+/*! Convert a 32-bit address to a 64-bit address. */
+static inline uint64
+fix_address(uint64 address)
+{
+ uint64 result;
+ if (platform_bootloader_address_to_kernel_address((void *)address,
&result) != B_OK)
+ return address;
+ else
+ return result;
+}
+
+template<typename Type>
+inline void
+fix_address(FixedWidthPointer<Type>& p)
+{
+ if (p != NULL)
+ p.SetTo(fix_address(p.Get()));
+}
+
+
int
smp_get_current_cpu(void)
{
@@ -250,7 +287,7 @@ smp_init_other_cpus(void)
panic("Unable to allocate AP stack");
}
memset(stack, 0, size);
- gKernelArgs.cpu_kstack[i].start = (uint64)stack;
+ gKernelArgs.cpu_kstack[i].start = fix_address((uint64_t)stack);
gKernelArgs.cpu_kstack[i].size = size;
}
}
@@ -307,47 +344,52 @@ smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64
kernel_entry)

// put the args in the right place
trampoline_args ** args_ptr =
- (trampoline_args **)(trampolineStack +
(uint64)smp_trampoline_args - (uint64)smp_trampoline);
+ (trampoline_args **)(trampolineCode +
(uint64)smp_trampoline_args - (uint64)smp_trampoline);
*args_ptr = args;

/* clear apic errors */
+ dprintf("clear apic errors\n");
if (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0) {
- apic_write(APIC_ERROR_STATUS, 0);
- apic_read(APIC_ERROR_STATUS);
+ dprintf("write to apic\n");
+ dprintf("apic at %p (%p)\n",
(void*)gKernelArgs.arch_args.apic, (void*)gKernelArgs.arch_args.apic_phys);
+ apic_write_phys(APIC_ERROR_STATUS, 0);
+ dprintf("read from apic\n");
+ apic_read_phys(APIC_ERROR_STATUS);
}
+ dprintf("done\n");

-//dprintf("assert INIT\n");
+dprintf("assert INIT\n");
/* send (aka assert) INIT IPI */
- config = (apic_read(APIC_INTR_COMMAND_2) &
APIC_INTR_COMMAND_2_MASK)
+ config = (apic_read_phys(APIC_INTR_COMMAND_2) &
APIC_INTR_COMMAND_2_MASK)
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
- apic_write(APIC_INTR_COMMAND_2, config); /* set target pe */
- config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000)
+ apic_write_phys(APIC_INTR_COMMAND_2, config); /* set target pe
*/
+ config = (apic_read_phys(APIC_INTR_COMMAND_1) & 0xfff00000)
| APIC_TRIGGER_MODE_LEVEL | APIC_INTR_COMMAND_1_ASSERT
| APIC_DELIVERY_MODE_INIT;
- apic_write(APIC_INTR_COMMAND_1, config);
+ apic_write_phys(APIC_INTR_COMMAND_1, config);

dprintf("wait for delivery\n");
// wait for pending to end
- while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS)
!= 0)
+ while ((apic_read_phys(APIC_INTR_COMMAND_1) &
APIC_DELIVERY_STATUS) != 0)
asm volatile ("pause;");

dprintf("deassert INIT\n");
/* deassert INIT */
- config = (apic_read(APIC_INTR_COMMAND_2) &
APIC_INTR_COMMAND_2_MASK)
+ config = (apic_read_phys(APIC_INTR_COMMAND_2) &
APIC_INTR_COMMAND_2_MASK)
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
- apic_write(APIC_INTR_COMMAND_2, config);
- config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff00000)
+ apic_write_phys(APIC_INTR_COMMAND_2, config);
+ config = (apic_read_phys(APIC_INTR_COMMAND_1) & 0xfff00000)
| APIC_TRIGGER_MODE_LEVEL | APIC_DELIVERY_MODE_INIT;
- apic_write(APIC_INTR_COMMAND_1, config);
+ apic_write_phys(APIC_INTR_COMMAND_1, config);

dprintf("wait for delivery\n");
// wait for pending to end
- while ((apic_read(APIC_INTR_COMMAND_1) & APIC_DELIVERY_STATUS)
!= 0)
+ while ((apic_read_phys(APIC_INTR_COMMAND_1) &
APIC_DELIVERY_STATUS) != 0)
asm volatile ("pause;");
-
+dprintf("spin a little\n");
/* wait 10ms */
spin(10000);
-
+dprintf("next phase...\n");
/* is this a local apic or an 82489dx ? */
numStartups = (gKernelArgs.arch_args.cpu_apic_version[i] & 0xf0)
? 2 : 0;
@@ -355,23 +397,23 @@ dprintf("num startups = %ld\n", numStartups);
for (j = 0; j < numStartups; j++) {
/* it's a local apic, so send STARTUP IPIs */
dprintf("send STARTUP\n");
- apic_write(APIC_ERROR_STATUS, 0);
+ apic_write_phys(APIC_ERROR_STATUS, 0);

/* set target pe */
- config = (apic_read(APIC_INTR_COMMAND_2) &
APIC_INTR_COMMAND_2_MASK)
+ config = (apic_read_phys(APIC_INTR_COMMAND_2) &
APIC_INTR_COMMAND_2_MASK)
| (gKernelArgs.arch_args.cpu_apic_id[i] << 24);
- apic_write(APIC_INTR_COMMAND_2, config);
+ apic_write_phys(APIC_INTR_COMMAND_2, config);

/* send the IPI */
- config = (apic_read(APIC_INTR_COMMAND_1) & 0xfff0f800)
+ config = (apic_read_phys(APIC_INTR_COMMAND_1) &
0xfff0f800)
| APIC_DELIVERY_MODE_STARTUP | (trampolineCode

12);
- apic_write(APIC_INTR_COMMAND_1, config);
+ apic_write_phys(APIC_INTR_COMMAND_1, config);

/* wait */
spin(200);

dprintf("wait for delivery\n");
- while ((apic_read(APIC_INTR_COMMAND_1) &
APIC_DELIVERY_STATUS) != 0)
+ while ((apic_read_phys(APIC_INTR_COMMAND_1) &
APIC_DELIVERY_STATUS) != 0)
asm volatile ("pause;");
}

diff --git a/src/system/boot/platform/efi/support.S
b/src/system/boot/platform/efi/support.S
index 58248c9..e351b13 100644
--- a/src/system/boot/platform/efi/support.S
+++ b/src/system/boot/platform/efi/support.S
@@ -38,24 +38,3 @@ FUNCTION(execute_n_instructions):
loop .again
ret

-FUNCTION(system_time):
- /* load 64-bit factor into %eax (low), %edx (high) */
- rdtsc /* time in %edx,%eax */
-
- push %rbx
- movl gTimeConversionFactor(%rip), %ebx
- movl (%rbx), %ebx
- movl %edx, %ecx /* save high half */
- mull %ebx /* truncate %eax, but keep %edx */
- movl %ecx, %eax
- movl %edx, %ecx /* save high half of low */
- mull %ebx /*, %eax*/
- /* now compute [%edx, %eax] + [%ecx], propagating carry */
- xorl %ebx, %ebx /* need zero to propagate carry */
- addl %ecx, %eax
- adc %ebx, %edx
- pop %rbx
- /* Convert to 64-bit result in rax. */
- shlq $32, %rdx
- orq %rdx, %rax
- ret

############################################################################

Commit: a88a807aafdd25d57c56f044b774066e51c08680
Author: Nick Smallbone <nick.smallbone@xxxxxxxxx>
Date: Sat May 2 21:54:02 2015 UTC
Committer: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Sat May 2 21:57:44 2015 UTC

Fix bug setting smp_trampoline_args.

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/smp.cpp
b/src/system/boot/platform/efi/smp.cpp
index 0f5a3dd..4e33849 100644
--- a/src/system/boot/platform/efi/smp.cpp
+++ b/src/system/boot/platform/efi/smp.cpp
@@ -343,9 +343,9 @@ smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64
kernel_entry)
args->sentinel = 1;

// put the args in the right place
- trampoline_args ** args_ptr =
- (trampoline_args **)(trampolineCode +
(uint64)smp_trampoline_args - (uint64)smp_trampoline);
- *args_ptr = args;
+ uint32 * args_ptr =
+ (uint32 *)(trampolineCode + (uint64)smp_trampoline_args
- (uint64)smp_trampoline);
+ *args_ptr = (uint32)(uint64)args;

/* clear apic errors */
dprintf("clear apic errors\n");

############################################################################

Commit: f3333f1435cd369f36a78265a2a60568736c635d
Author: Nick Smallbone <nick.smallbone@xxxxxxxxx>
Date: Sat May 2 22:25:15 2015 UTC
Committer: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Commit-Date: Sat May 2 22:30:47 2015 UTC

Fix several silly bugs in trampoline

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/entry.S
b/src/system/boot/platform/efi/entry.S
index 715ccec..2ff735f 100644
--- a/src/system/boot/platform/efi/entry.S
+++ b/src/system/boot/platform/efi/entry.S
@@ -25,7 +25,7 @@ FUNCTION(efi_enter_kernel):
movq %rdi, %cr3

// Load 64-bit enabled GDT
- lgdtq long_gdtr(%rip)
+ lgdtq gLongGDTR(%rip)

// Jump into the 64-bit code segment.
push $KERNEL_CODE_SELECTOR
@@ -62,7 +62,7 @@ FUNCTION(efi_enter_kernel):
.data


-long_gdtr:
+SYMBOL(gLongGDTR):
.word BOOT_GDT_SEGMENT_COUNT * 8 - 1
SYMBOL(gLongGDT):
.quad 0
diff --git a/src/system/boot/platform/efi/smp.cpp
b/src/system/boot/platform/efi/smp.cpp
index 4e33849..66f42d5 100644
--- a/src/system/boot/platform/efi/smp.cpp
+++ b/src/system/boot/platform/efi/smp.cpp
@@ -335,7 +335,7 @@ smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64
kernel_entry)
{0xff, 0xff, 0, 0, 0, 0x9a, 0xcf, 0},
{0xff, 0xff, 0, 0, 0, 0x92, 0xcf, 0}};
args->pml4 = pml4;
- args->gdt64 = gdt64;
+ args->gdt64 = gdtr64;
args->kernel_entry = kernel_entry;
args->kernel_args = (uint64)&gKernelArgs;
args->current_cpu = i;
diff --git a/src/system/boot/platform/efi/smp_trampoline.S
b/src/system/boot/platform/efi/smp_trampoline.S
index 3607f20..231150f 100644
--- a/src/system/boot/platform/efi/smp_trampoline.S
+++ b/src/system/boot/platform/efi/smp_trampoline.S
@@ -42,7 +42,8 @@ smp_trampoline_args:
movl %eax,%cr0

pushl $8
- pushl (trampoline_32 - smp_trampoline)(%ebx)
+ pushl (trampoline_32 - smp_trampoline)(%ebx), %eax
+ pushl %eax
.byte 0x66
.code32
retf
@@ -85,7 +86,8 @@ trampoline_32:

// Jump into the 64-bit code segment.
pushl $KERNEL_CODE_SELECTOR
- pushl (.Llmode - smp_trampoline)(%ebx)
+ pushl (.Llmode - smp_trampoline)(%ebx), %eax
+ pushl %eax
retf
.align 8
.code64
diff --git a/src/system/boot/platform/efi/start.cpp
b/src/system/boot/platform/efi/start.cpp
index 7175423..fa405f6 100644
--- a/src/system/boot/platform/efi/start.cpp
+++ b/src/system/boot/platform/efi/start.cpp
@@ -42,6 +42,7 @@ EFI_HANDLE kImage;
static uint32 sBootOptions;
static uint64 gLongKernelEntry;
extern uint64 gLongGDT;
+extern uint64 gLongGDTR;
segment_descriptor gBootGDT[BOOT_GDT_SEGMENT_COUNT];


@@ -271,7 +272,7 @@ platform_start_kernel(void)
// Update EFI, generate final kernel physical memory map, etc.
mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size,
descriptor_version);

- smp_boot_other_cpus(final_pml4, gLongGDT, gLongKernelEntry);
+ smp_boot_other_cpus(final_pml4, (uint32_t)(uint64_t)&gLongGDTR,
gLongKernelEntry);

// Enter the kernel!
efi_enter_kernel(final_pml4,

############################################################################

Commit: e3db0d1c79831a32b117eac4a0952df4fcb9ca3d
Author: Jessica Hamilton <jessica.l.hamilton@xxxxxxxxx>
Date: Sat May 2 22:57:42 2015 UTC

Fix up SMP, add some extra debugging for testing on actual hardware.

----------------------------------------------------------------------------

diff --git a/src/system/boot/platform/efi/debug.cpp
b/src/system/boot/platform/efi/debug.cpp
index 5e95aba..3b8ae99 100644
--- a/src/system/boot/platform/efi/debug.cpp
+++ b/src/system/boot/platform/efi/debug.cpp
@@ -76,7 +76,7 @@ dprintf_args(const char *format, va_list args)
serial_puts(buffer, length);

if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT)
- fprintf(stderr, "%s", buffer);
+ puts(buffer);
}


diff --git a/src/system/boot/platform/efi/smp.cpp
b/src/system/boot/platform/efi/smp.cpp
index 66f42d5..604cfad 100644
--- a/src/system/boot/platform/efi/smp.cpp
+++ b/src/system/boot/platform/efi/smp.cpp
@@ -293,7 +293,7 @@ smp_init_other_cpus(void)
}

void
-smp_boot_other_cpus(uint32 pml4, uint32 gdt64, uint64 kernel_entry)
+smp_boot_other_cpus(uint32 pml4, uint32 gdtr64, uint64 kernel_entry)
{
if (gKernelArgs.num_cpus < 2)
return;
diff --git a/src/system/boot/platform/efi/smp_trampoline.S
b/src/system/boot/platform/efi/smp_trampoline.S
index 231150f..48cebf4 100644
--- a/src/system/boot/platform/efi/smp_trampoline.S
+++ b/src/system/boot/platform/efi/smp_trampoline.S
@@ -42,7 +42,7 @@ smp_trampoline_args:
movl %eax,%cr0

pushl $8
- pushl (trampoline_32 - smp_trampoline)(%ebx), %eax
+ leal (trampoline_32 - smp_trampoline)(%ebx), %eax
pushl %eax
.byte 0x66
.code32
@@ -86,7 +86,7 @@ trampoline_32:

// Jump into the 64-bit code segment.
pushl $KERNEL_CODE_SELECTOR
- pushl (.Llmode - smp_trampoline)(%ebx), %eax
+ leal (.Llmode - smp_trampoline)(%ebx), %eax
pushl %eax
retf
.align 8
diff --git a/src/system/boot/platform/efi/start.cpp
b/src/system/boot/platform/efi/start.cpp
index fa405f6..58e049d 100644
--- a/src/system/boot/platform/efi/start.cpp
+++ b/src/system/boot/platform/efi/start.cpp
@@ -250,6 +250,7 @@ platform_start_kernel(void)
// A changing memory map shouldn't affect the generated page tables, as
// they only needed to know about the maximum address, not any specific
entry.
dprintf("Calling ExitBootServices. So long, EFI!\n");
+puts("Calling ExitBootServices");
while (1) {
if (kBootServices->ExitBootServices(kImage, map_key) ==
EFI_SUCCESS) {
break;
@@ -264,6 +265,7 @@ platform_start_kernel(void)

// The console was provided by boot services, disable it.
stdout = NULL;
+ stderr = NULL;

// Switch to BIOS serial output
serial_switch_to_bios();
@@ -272,8 +274,9 @@ platform_start_kernel(void)
// Update EFI, generate final kernel physical memory map, etc.
mmu_post_efi_setup(memory_map_size, memory_map, descriptor_size,
descriptor_version);

+puts("smp_boot_other cpus");
smp_boot_other_cpus(final_pml4, (uint32_t)(uint64_t)&gLongGDTR,
gLongKernelEntry);
-
+puts("efi_enter_kernel");
// Enter the kernel!
efi_enter_kernel(final_pml4,
gLongKernelEntry,
@@ -328,6 +331,7 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable)
serial_enable();
// interrupts_init();
console_init();
+ sBootOptions |= BOOT_OPTION_DEBUG_OUTPUT;
cpu_init();
// mmu_init();
debug_init_post_mmu();


Other related posts: