added 6 changesets to branch 'refs/remotes/tqh-github/efi_pm' old head: a1966568632a51e5383c56c2179a7c28932008cf new head: 7ab42dc22e60070c05a2bee21c5af4e5fbfe4203 overview: https://github.com/tqh/haiku/compare/a196656...7ab42dc ---------------------------------------------------------------------------- 52a0d86: GNU-EFI has removed the -S (strip-all) option, so do we. dfa63b1: Implement EFI keyboard functions. Mostly done. 8ac22ba: Implemented EFI serial code. Seems to work. Not sure we can pass EFI drivers to kernel so probably should remove commented kernel args section later. 19bc56a: Loop on EFI_NOT_READY when checking for keypress. Not sure 25e67aa: Partial implementation of EFI debug functions. Lacks implementation of debug_init_post_mmu and debug_cleanup 7ab42dc: Update Jamfile and work in progress on start.cpp Enable serial and early debug functions. [ Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ] ---------------------------------------------------------------------------- 10 files changed, 567 insertions(+), 17 deletions(-) src/system/boot/Jamfile | 2 +- src/system/boot/platform/efi/Jamfile | 6 +- src/system/boot/platform/efi/console.cpp | 13 +- src/system/boot/platform/efi/debug.cpp | 216 ++++++++++++++++++++++++++ src/system/boot/platform/efi/debug.h | 26 ++++ src/system/boot/platform/efi/keyboard.cpp | 75 +++++++++ src/system/boot/platform/efi/keyboard.h | 30 ++++ src/system/boot/platform/efi/serial.cpp | 128 +++++++++++++++ src/system/boot/platform/efi/serial.h | 29 ++++ src/system/boot/platform/efi/start.cpp | 59 +++++-- ############################################################################ Commit: 52a0d86e42316daf1c60df8e456a9bd302409899 Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sat Dec 14 23:04:33 2013 UTC GNU-EFI has removed the -S (strip-all) option, so do we. ---------------------------------------------------------------------------- diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index 3ea3628..acaedf2 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -131,7 +131,7 @@ rule BuildEFILoader { actions BuildEFILoader { rm -f $(1) $(TARGET_OBJCOPY_$(TARGET_PACKAGING_ARCH)) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ - -j .rela -j .reloc -S --target=efi-app-x86-64 $(2) $(1) + -j .rela -j .reloc --target=efi-app-x86-64 $(2) $(1) } BuildEFILoader haiku_loader.efi : boot_loader_$(TARGET_BOOT_PLATFORM) ; ############################################################################ Commit: dfa63b1c0050b313af99bf05cad06bc4d920a891 Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sat Dec 14 23:30:12 2013 UTC Implement EFI keyboard functions. Mostly done. ---------------------------------------------------------------------------- diff --git a/src/system/boot/platform/efi/keyboard.cpp b/src/system/boot/platform/efi/keyboard.cpp new file mode 100644 index 0000000..f7160e6 --- /dev/null +++ b/src/system/boot/platform/efi/keyboard.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2004-2011, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include "keyboard.h" + + +#include <boot/platform.h> +#include "efi_platform.h" + +/*! Note, checking for keys doesn't seem to work in graphics + mode, at least in Bochs. +*/ +static uint16 +check_for_key(void) +{ + EFI_INPUT_KEY key; + return (kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key) == + EFI_NOT_READY) ? 0 : key.UnicodeChar; +} + + +extern "C" void +clear_key_buffer(void) +{ + kSystemTable->ConIn->Reset(kSystemTable->ConIn, false); +} + + +extern "C" EFI_INPUT_KEY +wait_for_key(void) +{ + UINTN index; + EFI_INPUT_KEY key; + EFI_EVENT event = kSystemTable->ConIn->WaitForKey; + do { + kSystemTable->BootServices->WaitForEvent(1, &event, &index); + } while (kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key) + == EFI_NOT_READY); + + return key; +} + + +extern "C" uint32 +check_for_boot_keys(void) +{ +/* + bios_regs regs; + uint32 options = 0; + uint32 keycode = 0; + regs.eax = 0x0200; + call_bios(0x16, ®s); + // Read Keyboard flags. bit 0 LShift, bit 1 RShift + if ((regs.eax & 0x03) != 0) { + // LShift or RShift - option menu + options |= BOOT_OPTION_MENU; + } else { + keycode = boot_key_in_keyboard_buffer(); + if (keycode == 0x3920) { + // space - option menu + options |= BOOT_OPTION_MENU; + } else if (keycode == 0x011B) { + // ESC - debug output + options |= BOOT_OPTION_DEBUG_OUTPUT; + } + } +*/ +// dprintf("options = %ld\n", options); +// return options; + return 0; +} + diff --git a/src/system/boot/platform/efi/keyboard.h b/src/system/boot/platform/efi/keyboard.h new file mode 100644 index 0000000..fd45487 --- /dev/null +++ b/src/system/boot/platform/efi/keyboard.h @@ -0,0 +1,30 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + + +#include <SupportDefs.h> +#include "efi_platform.h" + + +#define BIOS_KEY_UP 0x48 +#define BIOS_KEY_DOWN 0x50 +#define BIOS_KEY_LEFT 0x4b +#define BIOS_KEY_RIGHT 0x4d +#define BIOS_KEY_HOME 0x47 +#define BIOS_KEY_END 0x4f +#define BIOS_KEY_PAGE_UP 0x49 +#define BIOS_KEY_PAGE_DOWN 0x51 + +#ifdef __cplusplus +extern "C" { +#endif + +extern void clear_key_buffer(void); +extern EFI_INPUT_KEY wait_for_key(void); +extern uint32 check_for_boot_keys(void); + +#ifdef __cplusplus +} +#endif + +#endif /* KEYBOARD_H */ ############################################################################ Commit: 8ac22ba815c77309c68651e7bbfb5c4ba9a644f0 Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sat Dec 14 23:37:18 2013 UTC Implemented EFI serial code. Seems to work. Not sure we can pass EFI drivers to kernel so probably should remove commented kernel args section later. ---------------------------------------------------------------------------- diff --git a/src/system/boot/platform/efi/serial.cpp b/src/system/boot/platform/efi/serial.cpp new file mode 100644 index 0000000..2a84af4 --- /dev/null +++ b/src/system/boot/platform/efi/serial.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2004-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include "efi_platform.h" +#include "efiser.h" +#include "serial.h" + +#include <boot/platform.h> +#include <arch/cpu.h> +#include <boot/stage2.h> + +#include <string.h> + + +//#define ENABLE_SERIAL + // define this to always enable serial output + + +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 EFI_GUID sSerialIOProtocolGUID = SERIAL_IO_PROTOCOL; +static const uint32 kSerialBaudRate = 115200; + +static SERIAL_IO_INTERFACE *sSerial = NULL; +static int32 sSerialEnabled = 0; + + +static void +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); +} + + +extern "C" void +serial_puts(const char* string, size_t size) +{ + if (sSerialEnabled <= 0 || sSerial == NULL) + return; + + //TODO: We can write strings instead of char by char. + while (size-- != 0) { + char c = string[0]; + + if (c == '\n') { + serial_putc('\r'); + serial_putc('\n'); + } else if (c != '\r') + serial_putc(c); + + string++; + } +} + + +extern "C" void +serial_disable(void) +{ +#ifdef ENABLE_SERIAL + sSerialEnabled = 0; +#else + sSerialEnabled--; +#endif +} + + +extern "C" void +serial_enable(void) +{ + sSerialEnabled++; +} + + +extern "C" void +serial_init(void) +{ + //Grab the first serial, we could grab handles and iterate if we want all.. + EFI_STATUS status = kSystemTable->BootServices->LocateProtocol( + &sSerialIOProtocolGUID, NULL, (void**)&sSerial); + + if (EFI_ERROR(status) || sSerial == NULL) { + sSerial = NULL; + return; + } + + // Setup serial, 0, 0 = Default Receive FIFO queue and default timeout + status = sSerial->SetAttributes(sSerial, kSerialBaudRate, 0, 0, NoParity, 8, + OneStopBit); + + if (EFI_ERROR(status)) { + sSerial = NULL; + return; + } + +/* TODO, this can probably be skipped. + // 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* ports = (uint16*)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]; +*/ + +#ifdef ENABLE_SERIAL + serial_enable(); +#endif +} diff --git a/src/system/boot/platform/efi/serial.h b/src/system/boot/platform/efi/serial.h new file mode 100644 index 0000000..03c5647 --- /dev/null +++ b/src/system/boot/platform/efi/serial.h @@ -0,0 +1,29 @@ +/* + * Copyright 2004-2007, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef SERIAL_H +#define SERIAL_H + + +#include <SupportDefs.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void serial_init(void); +extern void serial_init_post_mmu(void); +extern void serial_cleanup(void); + +extern void serial_puts(const char *string, size_t size); + +extern void serial_disable(void); +extern void serial_enable(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SERIAL_H */ ############################################################################ Commit: 19bc56af4540c644454cfe66de18b89fa5e9433b Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sat Dec 14 23:39:44 2013 UTC Loop on EFI_NOT_READY when checking for keypress. Not sure ---------------------------------------------------------------------------- diff --git a/src/system/boot/platform/efi/console.cpp b/src/system/boot/platform/efi/console.cpp index 4db2f29..04437b5 100644 --- a/src/system/boot/platform/efi/console.cpp +++ b/src/system/boot/platform/efi/console.cpp @@ -49,6 +49,7 @@ Console::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) ssize_t Console::WriteAt(void *cookie, off_t /*pos*/, const void *buffer, size_t bufferSize) { + const char *string = (const char *)buffer; CHAR16 ucsBuffer[bufferSize + 3]; uint32 j = 0; @@ -137,10 +138,14 @@ int console_wait_for_key(void) { UINTN index; - EFI_EVENT event = kSystemTable->ConIn->WaitForKey; - kSystemTable->BootServices->WaitForEvent(1, &event, &index); EFI_INPUT_KEY key; - kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key); + EFI_EVENT event = kSystemTable->ConIn->WaitForKey; + + do { + kSystemTable->BootServices->WaitForEvent(1, &event, &index); + } while (kSystemTable->ConIn->ReadKeyStroke(kSystemTable->ConIn, &key) + == EFI_NOT_READY); + if (key.UnicodeChar > 0) return (int) key.UnicodeChar; @@ -180,6 +185,8 @@ console_init(void) { updateScreenSize(); console_clear_screen(); + console_clear_screen(); + // enable stdio functionality stdin = (FILE *)&sInput; stdout = stderr = (FILE *)&sOutput; ############################################################################ Commit: 25e67aa20410a52d3193572a2b0eea4074ae8144 Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sat Dec 14 23:48:10 2013 UTC Partial implementation of EFI debug functions. Lacks implementation of debug_init_post_mmu and debug_cleanup ---------------------------------------------------------------------------- diff --git a/src/system/boot/platform/efi/debug.cpp b/src/system/boot/platform/efi/debug.cpp new file mode 100644 index 0000000..94dc789 --- /dev/null +++ b/src/system/boot/platform/efi/debug.cpp @@ -0,0 +1,216 @@ +/* + * Copyright 2004-2007, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include "debug.h" + +#include <string.h> + +#include <boot/platform.h> +#include <boot/stage2.h> +#include <boot/stdio.h> +#include <kernel.h> +#include <util/ring_buffer.h> + +#include "keyboard.h" +#include "mmu.h" +#include "serial.h" + + +//#define PRINT_TIME_STAMPS + // Define to print a TSC timestamp before each line of output. + + +static const char* const kDebugSyslogSignature = "Haiku syslog"; + +static char sBuffer[16384]; +static uint32 sBufferPosition; + +static ring_buffer* sDebugSyslogBuffer = NULL; +static bool sPostCleanup = false; + + +#ifdef PRINT_TIME_STAMPS +extern "C" uint64 rdtsc(); +#endif + + +static void +syslog_write(const char* buffer, size_t length) +{ + if (sPostCleanup && sDebugSyslogBuffer != NULL) { + ring_buffer_write(sDebugSyslogBuffer, (const uint8*)buffer, length); + } else if (sBufferPosition + length < sizeof(sBuffer)) { + memcpy(sBuffer + sBufferPosition, buffer, length); + sBufferPosition += length; + } +} + + +static void +dprintf_args(const char *format, va_list args) +{ + char buffer[512]; + int length = vsnprintf(buffer, sizeof(buffer), format, args); + if (length == 0) + return; + + if (length >= (int)sizeof(buffer)) + length = sizeof(buffer) - 1; + +#ifdef PRINT_TIME_STAMPS + static bool sNewLine = true; + + if (sNewLine) { + char timeBuffer[32]; + snprintf(timeBuffer, sizeof(timeBuffer), "[%" B_PRIu64 "] ", rdtsc()); + syslog_write(timeBuffer, strlen(timeBuffer)); + serial_puts(timeBuffer, strlen(timeBuffer)); + } + + sNewLine = buffer[length - 1] == '\n'; +#endif // PRINT_TIME_STAMPS + + syslog_write(buffer, length); + serial_puts(buffer, length); + + if (platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) + fprintf(stderr, "%s", buffer); +} + + +// #pragma mark - + + +/*! This works only after console_init() was called. +*/ +void +panic(const char *format, ...) +{ + va_list list; + + platform_switch_to_text_mode(); + + puts("*** PANIC ***"); + + va_start(list, format); + vprintf(format, list); + va_end(list); + + puts("\nPress key to reboot."); + + clear_key_buffer(); + wait_for_key(); + platform_exit(); +} + + +void +dprintf(const char *format, ...) +{ + va_list args; + + va_start(args, format); + dprintf_args(format, args); + va_end(args); +} + + +void +kprintf(const char *format, ...) +{ + va_list args; + + va_start(args, format); + + // print to console, if available + if (stdout != NULL) + vfprintf(stdout, format, args); + + // always print to serial line + dprintf_args(format, args); + + va_end(args); +} + + +// #pragma mark - + + +void +debug_init_post_mmu(void) +{ +/* + // allocate 1 MB memory at 63 MB + addr_t base = 63 * 1024 * 1024; + size_t size = 1024 * 1024; + if (!mmu_allocate_physical(base, size)) + return; + + void* buffer = (void*)mmu_map_physical_memory(base, size, + kDefaultPageFlags); + if (buffer == NULL) + return; + + // check whether there's a previous syslog we can recover + size_t signatureLength = strlen(kDebugSyslogSignature); + bool recover = memcmp(buffer, kDebugSyslogSignature, signatureLength) == 0; + + size -= signatureLength; + buffer = (uint8*)buffer + ROUNDUP(signatureLength, sizeof(void*)); + + sDebugSyslogBuffer = create_ring_buffer_etc(buffer, size, + recover ? RING_BUFFER_INIT_FROM_BUFFER : 0); + + gKernelArgs.debug_output = sDebugSyslogBuffer; + gKernelArgs.debug_size = sDebugSyslogBuffer->size; +*/ +} + + +void +debug_cleanup(void) +{ +/* + if (sDebugSyslogBuffer != NULL) { + size_t signatureLength = strlen(kDebugSyslogSignature); + void* buffer + = (void*)ROUNDDOWN((addr_t)sDebugSyslogBuffer, B_PAGE_SIZE); + + if (gKernelArgs.keep_debug_output_buffer) { + // copy the output gathered so far into the ring buffer + ring_buffer_clear(sDebugSyslogBuffer); + ring_buffer_write(sDebugSyslogBuffer, (uint8*)sBuffer, + sBufferPosition); + + memcpy(buffer, kDebugSyslogSignature, signatureLength); + } else { + // clear the signature + memset(buffer, 0, signatureLength); + } + } else + gKernelArgs.keep_debug_output_buffer = false; + + if (!gKernelArgs.keep_debug_output_buffer) { + gKernelArgs.debug_output = kernel_args_malloc(sBufferPosition); + if (gKernelArgs.debug_output != NULL) { + memcpy(gKernelArgs.debug_output, sBuffer, sBufferPosition); + gKernelArgs.debug_size = sBufferPosition; + } + } + + sPostCleanup = true; +*/ +} + + +char* +platform_debug_get_log_buffer(size_t* _size) +{ + if (_size != NULL) + *_size = sizeof(sBuffer); + + return sBuffer; +} diff --git a/src/system/boot/platform/efi/debug.h b/src/system/boot/platform/efi/debug.h new file mode 100644 index 0000000..7ed19d6 --- /dev/null +++ b/src/system/boot/platform/efi/debug.h @@ -0,0 +1,26 @@ +/* + * + * + */ +#ifndef DEBUG_H +#define DEBUG_H + + +#include <stdarg.h> + +#include <SupportDefs.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +void debug_init_post_mmu(void); +void debug_cleanup(void); + +#ifdef __cplusplus +} +#endif + + +#endif // DEBUG_H ############################################################################ Commit: 7ab42dc22e60070c05a2bee21c5af4e5fbfe4203 Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sat Dec 14 23:49:53 2013 UTC Update Jamfile and work in progress on start.cpp Enable serial and early debug functions. ---------------------------------------------------------------------------- diff --git a/src/system/boot/platform/efi/Jamfile b/src/system/boot/platform/efi/Jamfile index 4e92da3..c99ee59 100644 --- a/src/system/boot/platform/efi/Jamfile +++ b/src/system/boot/platform/efi/Jamfile @@ -18,13 +18,15 @@ local efi_glue_src = ; BootMergeObject boot_platform_efi.o : - start.cpp console.cpp -# debug.cpp + debug.cpp # devices.cpp + start.cpp # interrupts.cpp # interrupts_asm.S + keyboard.cpp # mmu.cpp + serial.cpp $(efi_glue_src) : : boot_platform_generic.a diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp index 1831efa..67a55e5 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -12,12 +12,24 @@ #include <boot/platform.h> #include <boot/heap.h> #include <boot/stage2.h> -#include <stdio.h> - -#include "efi_platform.h" +//#include "acpi.h" +//#include "apm.h" +//#include "bios.h" #include "console.h" -#include "interrupts.h" +//#include "cpu.h" +#include "debug.h" +//#include "hpet.h" +//#include "interrupts.h" +#include "keyboard.h" +//#include "long.h" +#include "mmu.h" +//#include "multiboot.h" +#include "serial.h" +//#include "smp.h" + + +#define HEAP_SIZE ((1024 + 256) * 1024) extern void (*__ctor_list)(void); @@ -29,6 +41,10 @@ extern uint8 _end; const EFI_SYSTEM_TABLE *kSystemTable; +extern "C" int main(stage2_args *args); +extern "C" void _start(void); + + static void clear_bss(void) { @@ -47,6 +63,25 @@ call_ctors(void) } +extern "C" uint32 +platform_boot_options(void) +{ + return 0; +} + + +extern "C" void +platform_start_kernel(void) +{ +} + + +extern "C" void +platform_exit(void) +{ +} + + /** * efi_main - The entry point for the EFI application * @image: firmware-allocated handle that identifies the image @@ -71,13 +106,14 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) //Do all the necessary things needed... - /* serial - ignore for now */ - /* interrupts_init(); */ + serial_init(); + serial_enable(); +// interrupts_init(); console_init(); - /* console - EFI console handling */ - /* cpu init - TODO */ - /* mmu init - TODO */ - /* debug_init_post_mmu - TODO */ +// cpu_init(); +// mmu_init(); + debug_init_post_mmu(); + /* parse_multiboot_commandline - probably not */ /* check for boot keys */ @@ -99,7 +135,8 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systemTable) * See info on memory map and much more in docs. */ //launch kernel (main(&args);) - + //main(&args); + dprintf(("hello world!\n")); console_wait_for_key(); return EFI_SUCCESS; }