bsps/amd64: add a new EFI-based variant of AMD64 BSP

The new amd64efi BSP supports:
- multiboot2 boot format. Runs well with GRUB.
- console based on either EFI simple text output or GOP-based framebuffer
- clock based on EFI event/timer API
- early console using either hard-wired PC-AT serial or just memory buffer
- with EFI support disabled the BSP is more or less equivalent to amd64 BSP
  with multiboot2 support
This commit is contained in:
Karel Gardas
2023-04-16 23:01:58 +02:00
parent 1590df5f9a
commit bf53ff2de2
27 changed files with 7253 additions and 5 deletions

View File

@@ -0,0 +1,109 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <efi.h>
#include <stdio.h>
extern EFI_BOOT_SERVICES *BS;
static EFI_EVENT clock_event = 0;
extern void
Clock_isr( void* );
#ifndef EFIAPI
#error "EFIAPI not defined!"
#endif
/* no-sse attribute helps with enforcing GCC to generate code which does not use
SSE instructions requiring 16 byte alligned access on unaligned data hence
producing perfect GP fault. The code with SSE enabled looks:
EFIAPI void
efi_clock_tick_notify(EFI_EVENT e, VOID* ctx)
{
10b2ba: 55 push rbp
10b2bb: 48 89 e5 mov rbp,rsp
10b2be: 57 push rdi
10b2bf: 56 push rsi
10b2c0: 48 81 ec a0 00 00 00 sub rsp,0xa0
10b2c7: 8b 02 mov eax,DWORD PTR [rdx]
->10b2c9: 0f 29 b5 50 ff ff ff movaps XMMWORD PTR [rbp-0xb0],xmm6
10b2d0: 0f 29 bd 60 ff ff ff movaps XMMWORD PTR [rbp-0xa0],xmm7
10b2d7: 83 c0 01 add eax,0x1
and we get GP @ 10b2c9.
CAVEAT: This function is to be called from the UEFI which means it needs to callable
by using MS ABI!
*/
__attribute__((target("no-sse")))
EFIAPI void
efi_clock_tick_notify(EFI_EVENT e, VOID* ctx);
__attribute__((target("no-sse")))
EFIAPI void
efi_clock_tick_notify(EFI_EVENT e, VOID* ctx)
{
Clock_isr(NULL);
}
static void
efi_clock_initialize( void )
{
EFI_STATUS status = BS->CreateEvent
(EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK, (EFI_EVENT_NOTIFY)efi_clock_tick_notify,
(VOID*)NULL, &clock_event);
if (EFI_ERROR(status)) {
printf("EFI: error while creating event in clock initialization!\n");
}
else {
printf("EFI: clock event created.\n");
/* set periodic timer to signal Clock_isr every 10 milisecond. Value provided
here is following UEFI spec in hundred of nanoseconds. */
status = BS->SetTimer(clock_event, TimerPeriodic, (10 * 1000 * 10));
if (EFI_ERROR(status)) {
printf("EFI: error while creating timer in clock initialization!\n");
BS->CloseEvent(clock_event);
}
else {
printf("EFI: timer for clock event is set.\n");
}
}
}
#define Clock_driver_support_initialize_hardware() efi_clock_initialize()
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
/* Include shared source clock driver code */
#include "../../shared/dev/clock/clockimpl.h"

View File

@@ -30,6 +30,9 @@
#include <bsp/console-termios.h>
#include <rtems/score/cpuimpl.h>
void
uart0_output_char(char);
static uint8_t amd64_uart_get_register(uintptr_t addr, uint8_t i)
{
return inport_byte(addr + i);
@@ -61,12 +64,16 @@ const console_device console_device_table[] = {
};
const size_t console_device_count = RTEMS_ARRAY_SIZE(console_device_table);
static void output_char(char c)
void uart0_output_char(char c)
{
rtems_termios_device_context *ctx = console_device_table[0].context;
ns16550_polled_putchar(ctx, c);
}
BSP_output_char_function_type BSP_output_char = output_char;
#ifndef BSP_USE_EFI_BOOT_SERVICES
BSP_output_char_function_type BSP_output_char = uart0_output_char;
BSP_polling_getchar_function_type BSP_poll_char = NULL;
#endif

View File

@@ -0,0 +1,250 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <efi.h>
#include <rtems/bspIo.h>
#include <stdio.h>
#include <string.h>
#include <efistop.h>
#include <efigop.h>
#include <multiboot2impl.h>
#ifdef BSP_USE_EFI_BOOT_SERVICES
extern EFI_HANDLE IH;
extern EFI_SYSTEM_TABLE *ST;
extern EFI_BOOT_SERVICES *BS;
extern EFI_RUNTIME_SERVICES *RS;
extern void uart0_output_char(char c);
static bool is_efi_console_initialized = false;
static char output_buffer[4096];
static int output_buffer_index = 0;
void
efi_console_initialize(void);
EFI_STATUS
print_gop_info(EFI_GRAPHICS_OUTPUT *gop);
EFI_STATUS
check_gop(BOOLEAN verbose);
static void
both_output_char(char c);
static void
sync_output(void);
void
print_ccm_info(EFI_CONSOLE_CONTROL_SCREEN_MODE, BOOLEAN, BOOLEAN);
void
print_ccm_info(EFI_CONSOLE_CONTROL_SCREEN_MODE mode, BOOLEAN graphics, BOOLEAN locked)
{
printf("RTEMS: EFI console default mode: ");
switch (mode) {
case EfiConsoleControlScreenText:
printf("text");
break;
case EfiConsoleControlScreenGraphics:
printf("graphics");
break;
case EfiConsoleControlScreenMaxValue:
printf("max value");
break;
}
if (graphics) {
printf(", graphics is available");
}
if (locked) {
printf(", stdin is locked");
}
printf("\n");
}
void
efi_console_initialize( void )
{
EFI_STATUS status;
EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
EFI_HANDLE *HandleBuffer = NULL;
UINTN HandleCount = 0;
BOOLEAN graphics_exists;
BOOLEAN locked_stdin;
EFI_CONSOLE_CONTROL_SCREEN_MODE mode;
BOOLEAN use_text = false;
BOOLEAN use_graphic = false;
BOOLEAN use_auto = false;
int text_mode = -1;
int graphic_mode = -1;
if (is_efi_console_initialized)
return;
if (ST == NULL)
return;
/* try hard to obtain console control */
status = ST->BootServices->LocateProtocol(&ConsoleControlGUID, NULL,
(VOID **)&ConsoleControl);
if (EFI_ERROR(status)) {
status = ST->BootServices->HandleProtocol( ST->ConsoleOutHandle,
&ConsoleControlGUID,
(VOID **)&ConsoleControl);
if (EFI_ERROR(status)) {
status = ST->BootServices->LocateHandleBuffer( ByProtocol,
&ConsoleControlGUID,
NULL,
&HandleCount,
&HandleBuffer);
if (status == EFI_SUCCESS) {
for (int i = 0; i < HandleCount; i++) {
status = ST->BootServices->HandleProtocol( HandleBuffer[i],
&ConsoleControlGUID,
(VOID*)&ConsoleControl);
if (!EFI_ERROR (status)) {
break;
}
}
ST->BootServices->FreePool(HandleBuffer);
}
}
}
if (strcmp(BSP_EFI_CONSOLE_KIND, "TEXT") == 0) {
use_text = true;
}
if (strcmp(BSP_EFI_CONSOLE_KIND, "GRAPHIC") == 0) {
use_graphic = true;
}
if (strcmp(BSP_EFI_CONSOLE_KIND, "BOTH") == 0) {
use_text = true;
use_graphic = true;
}
if (strcmp(BSP_EFI_CONSOLE_KIND, "AUTO") == 0) {
use_auto = true;
}
if (ConsoleControl != NULL) {
status = ConsoleControl->GetMode(ConsoleControl, &mode, &graphics_exists, &locked_stdin);
if (!EFI_ERROR(status)) {
print_ccm_info(mode, graphics_exists, locked_stdin);
if (mode == EfiConsoleControlScreenText && use_auto) {
use_text = true;
}
if (mode == EfiConsoleControlScreenGraphics && use_auto) {
use_graphic = true;
}
}
else {
/* in case of error from console control, let's use both outputs */
use_text = true;
use_graphic = true;
}
}
else {
/* in case of missing console control, let's use both outputs */
use_text = true;
use_graphic = true;
}
if (get_boot_arg_int_value(boot_args(), "text_mode", &text_mode) == 0
|| get_boot_arg_int_value(boot_args(), "graphic_mode", &graphic_mode) == 0) {
/* if there is any command-line arg passed to manage console, we give it max
priority which means we reset any value set so far. */
use_text = false;
use_graphic = false;
}
if (get_boot_arg_int_value(boot_args(), "text_mode", &text_mode) == 0) {
use_text = true;
}
if (get_boot_arg_int_value(boot_args(), "graphic_mode", &graphic_mode) == 0) {
use_graphic = true;
}
if (use_text)
efi_init_text_output(text_mode);
if (use_graphic) {
efi_init_graphic_output(graphic_mode);
}
if (use_text && use_graphic) {
BSP_output_char = both_output_char;
}
else if (use_text) {
BSP_output_char = efi_text_output_char;
}
else if (use_graphic) {
BSP_output_char = efi_graphic_output_char;
}
sync_output();
is_efi_console_initialized = true;
}
void
buffered_output( char c );
void
buffered_output( char c )
{
if (output_buffer_index < (4096 - 1)) {
output_buffer[output_buffer_index] = c;
output_buffer_index++;
}
}
static void
both_output_char( char c )
{
efi_text_output_char(c);
efi_graphic_output_char(c);
}
void
sync_output()
{
printf("EFI: console sync_output(): there are %d characters in the buffer.\n", output_buffer_index);
for (int i = 0; i < output_buffer_index; i++) {
BSP_output_char(output_buffer[i]);
}
printf("EFI: console sync_output() done.\n");
}
#if (BSP_EFI_EARLY_CONSOLE_KIND == BUFFER)
BSP_output_char_function_type BSP_output_char = buffered_output;
#elif (BSP_EFI_EARLY_CONSOLE_KIND == SERIAL)
BSP_output_char_function_type BSP_output_char = uart0_output_char;
#endif
BSP_polling_getchar_function_type BSP_poll_char = NULL;
#endif

View File

@@ -0,0 +1,374 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <efi.h>
#include <rtems/bspIo.h>
#include <rtems/framebuffer.h>
#include <rtems/fb.h>
#include <rtems/score/atomic.h>
#include <rtems/libio.h>
#include <efigop.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef BSP_USE_EFI_BOOT_SERVICES
static Atomic_Flag driver_mutex;
extern EFI_SYSTEM_TABLE *ST;
extern EFI_BOOT_SERVICES *BS;
static struct fb_var_screeninfo gopfb_var = {
.xres = 0,
.yres = 0,
.bits_per_pixel = 32
};
static struct fb_fix_screeninfo gopfb_fix = {
.smem_start = NULL,
.smem_len = 0,
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.line_length = 0
};
static EFI_GRAPHICS_OUTPUT*
find_gop(void);
static int
init_gop(EFI_GRAPHICS_OUTPUT*, int);
static int
init_fb_from_gop(EFI_GRAPHICS_OUTPUT *gop, struct fb_var_screeninfo* fbvar, struct fb_fix_screeninfo* fbfix);
extern void rpi_fb_outch(char);
extern void rpi_video_init(void);
void
efi_graphic_output_char(char c)
{
rpi_fb_outch(c);
}
rtems_device_driver
frame_buffer_initialize
(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_status_code status;
status = rtems_io_register_name(FRAMEBUFFER_DEVICE_0_NAME, major, 0);
if (status != RTEMS_SUCCESSFUL) {
printf("EFI/GOP: error: can't register /dev/fb0 device.\n");
rtems_fatal_error_occurred(status);
}
_Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0) {
printf("EFI/GOP: error: can't lock device mutex.\n" );
return RTEMS_UNSATISFIED;
}
return RTEMS_SUCCESSFUL;
}
rtems_device_driver
frame_buffer_open
(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0) {
printf("EFI/GOP: error: can't lock device mutex.\n" );
return RTEMS_UNSATISFIED;
}
if (gopfb_fix.smem_start == NULL) {
_Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
printf( "EFI/GOP: framebuffer initialization failed.\n" );
return RTEMS_UNSATISFIED;
}
memset( (void *) gopfb_fix.smem_start, 255, gopfb_fix.smem_len );
return RTEMS_SUCCESSFUL;
}
rtems_device_driver
frame_buffer_close
(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
_Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
return RTEMS_SUCCESSFUL;
}
rtems_device_driver
frame_buffer_read
(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_libio_rw_args_t* rw_args = (rtems_libio_rw_args_t*)arg;
rw_args->bytes_moved =
(( rw_args->offset + rw_args->count) > gopfb_fix.smem_len) ?
(gopfb_fix.smem_len - rw_args->offset) : rw_args->count;
memcpy( rw_args->buffer,
(const void *)(gopfb_fix.smem_start + rw_args->offset),
rw_args->bytes_moved);
return RTEMS_SUCCESSFUL;
}
rtems_device_driver
frame_buffer_write
(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_libio_rw_args_t* rw_args = (rtems_libio_rw_args_t*)arg;
rw_args->bytes_moved =
((rw_args->offset + rw_args->count) > gopfb_fix.smem_len) ?
(gopfb_fix.smem_len - rw_args->offset) : rw_args->count;
memcpy((void *)(gopfb_fix.smem_start + rw_args->offset),
rw_args->buffer,
rw_args->bytes_moved);
return RTEMS_SUCCESSFUL;
}
rtems_device_driver
frame_buffer_control
(rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_libio_ioctl_args_t* args = (rtems_libio_ioctl_args_t*)arg;
switch (args->command) {
case FBIOGET_VSCREENINFO:
memcpy(args->buffer, &gopfb_var, sizeof(struct fb_var_screeninfo));
args->ioctl_return = 0;
break;
case FBIOGET_FSCREENINFO:
memcpy(args->buffer, &gopfb_fix, sizeof(struct fb_fix_screeninfo));
args->ioctl_return = 0;
break;
case FBIOGETCMAP:
/* no palette - truecolor mode */
args->ioctl_return = -1;
return RTEMS_UNSATISFIED;
case FBIOPUTCMAP:
/* no palette - truecolor mode */
args->ioctl_return = -1;
return RTEMS_UNSATISFIED;
default:
args->ioctl_return = -1;
return RTEMS_UNSATISFIED;
}
return RTEMS_SUCCESSFUL;
}
int
efi_init_graphic_output(int hint)
{
EFI_GRAPHICS_OUTPUT* gop = find_gop();
if (gop == NULL) {
printf("EFI: GOP is not available\n");
return RTEMS_UNSATISFIED;
}
if (init_gop(gop, hint) < 0) {
return RTEMS_UNSATISFIED;
}
init_fb_from_gop(gop, &gopfb_var, &gopfb_fix);
/* init RPi based character output */
rpi_video_init();
memset( (void *) gopfb_fix.smem_start, 255, gopfb_fix.smem_len );
return RTEMS_SUCCESSFUL;
}
static int
init_gop(EFI_GRAPHICS_OUTPUT *gop, int hint)
{
EFI_STATUS status;
if (gop == NULL)
return -1;
int imax = gop->Mode->MaxMode - 1;
if (hint != -1) {
/* hint got from command-line does have highest priority */
status = gop->SetMode(gop, hint);
if (EFI_ERROR(status)) {
printf("EFI/GOP: can't set mode to: %d which was set on command line.\n", hint);
return -1;
}
}
else if (strcmp(BSP_EFI_GRAPHICS_OUTPUT_MODE_VALUE, "MAX") == 0) {
status = gop->SetMode(gop, imax);
if (EFI_ERROR(status)) {
printf("EFI/GOP: can't set mode to: %d which should be MAX\n", imax);
return -1;
}
}
else if (strcmp(BSP_EFI_GRAPHICS_OUTPUT_MODE_VALUE, "AUTO") == 0) {
status = gop->SetMode(gop, gop->Mode->Mode);
if (EFI_ERROR(status)) {
printf("EFI/GOP: can't set mode to: %d which should be AUTO (platform preferred value)\n", imax);
return -1;
}
}
else {
int vmode = atoi(BSP_EFI_GRAPHICS_OUTPUT_MODE_VALUE);
status = gop->SetMode(gop, vmode);
if (EFI_ERROR(status)) {
printf("EFI/GOP: can't set mode to: %d which is used supplied value.\n", vmode);
return -1;
}
}
return 0;
}
static int
init_fb_from_gop(EFI_GRAPHICS_OUTPUT *gop, struct fb_var_screeninfo* fbvar, struct fb_fix_screeninfo* fbfix)
{
int i, imax;
EFI_STATUS status;
if (gop == NULL)
return -1;
imax = gop->Mode->MaxMode;
printf("RTEMS: graphic output: current mode: %d, max mode: %d.\n", gop->Mode->Mode, (imax - 1));
for (i = 0; i < imax; i++) {
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = NULL;
UINTN SizeOfInfo = 0;
status = gop->QueryMode(gop, i, &SizeOfInfo, &Info);
if (EFI_ERROR(status) && status == EFI_NOT_STARTED) {
gop->SetMode(gop, gop->Mode->Mode);
status = gop->QueryMode(gop, i, &SizeOfInfo, &Info);
}
if (EFI_ERROR(status)) {
printf("ERROR: Bad response from QueryMode: %ld\n", status);
continue;
}
printf("%s%d: %dx%d ", memcmp(Info,gop->Mode->Info,sizeof(*Info)) == 0 ? " -> " : " ", i,
Info->HorizontalResolution,
Info->VerticalResolution);
switch(Info->PixelFormat) {
case PixelRedGreenBlueReserved8BitPerColor:
printf("RGBR format, FB @ %p, size: %ld", (void*)gop->Mode->FrameBufferBase, gop->Mode->FrameBufferSize);
break;
case PixelBlueGreenRedReserved8BitPerColor:
printf("BGRR format, FB @ %p, size: %ld", (void*)gop->Mode->FrameBufferBase, gop->Mode->FrameBufferSize);
break;
case PixelBitMask:
printf("Red:%08x Green:%08x Blue:%08x Reserved:%08x",
Info->PixelInformation.RedMask,
Info->PixelInformation.GreenMask,
Info->PixelInformation.BlueMask,
Info->PixelInformation.ReservedMask);
break;
case PixelBltOnly:
printf("(linear fb not available)");
break;
default:
printf("(invalid format)");
break;
}
printf(", %d pixels per line\n", Info->PixelsPerScanLine);
}
fbvar->xres = gop->Mode->Info->HorizontalResolution;
fbvar->yres = gop->Mode->Info->VerticalResolution;
fbfix->smem_start = (void*)gop->Mode->FrameBufferBase;
fbfix->smem_len = gop->Mode->FrameBufferSize;
fbfix->line_length = gop->Mode->Info->PixelsPerScanLine;
return EFI_SUCCESS;
}
static EFI_GRAPHICS_OUTPUT*
find_gop()
{
EFI_HANDLE *HandleBuffer = NULL;
UINTN HandleCount = 0;
EFI_STATUS status = EFI_SUCCESS;
EFI_GRAPHICS_OUTPUT *gop = NULL;
EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
status = BS->HandleProtocol(ST->ConsoleOutHandle,
&gop_guid,
(VOID **)&gop);
if (!EFI_ERROR (status) && gop != NULL) {
return gop;
}
status = BS->LocateProtocol(&gop_guid, NULL, (void**)&gop);
if (!EFI_ERROR (status) && gop != NULL) {
return gop;
}
// try locating by handle
status = BS->LocateHandleBuffer(ByProtocol,
&gop_guid,
NULL,
&HandleCount,
&HandleBuffer);
if (!EFI_ERROR (status)) {
for (int i = 0; i < HandleCount; i++) {
status = BS->HandleProtocol( HandleBuffer[i],
&gop_guid,
(VOID*)&gop);
if (!EFI_ERROR (status)) {
break;
}
}
BS->FreePool(HandleBuffer);
return gop;
}
return NULL;
}
void
rpi_get_var_screen_info(struct fb_var_screeninfo* info)
{
*info = gopfb_var;
}
void
rpi_get_fix_screen_info(struct fb_fix_screeninfo* info)
{
*info = gopfb_fix;
}
#endif

View File

@@ -0,0 +1,107 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <efi.h>
#include <efilib.h>
#include <rtems/bspIo.h>
#include <efistop.h>
#include <stdio.h>
#include <string.h>
#ifdef BSP_USE_EFI_BOOT_SERVICES
static void
print_stop_info(SIMPLE_TEXT_OUTPUT_INTERFACE* stop);
void
efi_init_text_output(int hint)
{
int maxval = ST->ConOut->Mode->MaxMode - 1;
int curval = ST->ConOut->Mode->Mode;
ST->ConOut->Reset(ST->ConOut, true);
if (hint != -1) {
/* hint got from command-line does have highest priority */
ST->ConOut->SetMode(ST->ConOut, hint);
}
else if (strcmp(BSP_EFI_SIMPLE_TEXT_OUTPUT_MODE_VALUE, "MAX") == 0) {
ST->ConOut->SetMode(ST->ConOut, maxval);
}
else if (strcmp(BSP_EFI_SIMPLE_TEXT_OUTPUT_MODE_VALUE, "AUTO") == 0) {
ST->ConOut->SetMode(ST->ConOut, curval);
}
else {
ST->ConOut->SetMode(ST->ConOut, atoi(BSP_EFI_SIMPLE_TEXT_OUTPUT_MODE_VALUE));
}
ST->ConOut->EnableCursor(ST->ConOut, TRUE);
print_stop_info(ST->ConOut);
ST->ConOut->ClearScreen(ST->ConOut);
}
void
efi_text_output_char(char c)
{
EFI_STATUS status;
char tocpy[2];
tocpy[0] = c;
tocpy[1] = 0;
CHAR16 str[2];
cpy8to16(tocpy, str, 2);
status = ST->ConOut->TestString(ST->ConOut, str);
if (EFI_ERROR(status))
str[0] = '?';
ST->ConOut->OutputString(ST->ConOut, str);
}
static void
print_stop_info(SIMPLE_TEXT_OUTPUT_INTERFACE* stop)
{
EFI_STATUS status;
int max_mode = stop->Mode->MaxMode;
int current_mode = stop->Mode->Mode;
printf("RTEMS: text output: current mode: %d, max mode: %d\n", current_mode, (max_mode - 1));
UINTN columns = 0;
UINTN rows = 0;
for (int i = 0; i < max_mode; i++) {
if (current_mode == i)
printf(" -> ");
else
printf(" ");
status = stop->QueryMode(stop, i, &columns, &rows);
if (EFI_ERROR(status))
printf("%d. mode: error: can't obtain column x row values.\n", i);
else {
printf("%d. mode: %ld * %ld\n", i, columns, rows);
}
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,461 @@
/**
* @file
*
* @ingroup amd64
*
* @brief displaying characters on the console
*
* NOTE: This file is copied from arm/raspberrypi BSP.
* It is only slightly changed to work with EFI GOP.
* Obvious idea is to refactor whole framebuffer console
* business shared between various BSPs and move that
* properly to bsps/shared and reuse.
*/
/**
*
* Copyright (c) 2015 Yang Qiao
* based on work by:
* Copyright (C) 1998 Eric Valette (valette@crf.canon.fr)
* Canon Centre Recherche France.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*
* Till Straumann <strauman@slac.stanford.edu>, 2003/9:
* - added handling of basic escape sequences (cursor movement
* and erasing; just enough for the line editor 'libtecla' to
* work...)
*
*/
#include <bsp.h>
#include <rtems/fb.h>
#include <efigop.h>
#include <stdlib.h>
#include <string.h>
#include "font_data.h"
static void wr_cursor(
int r,
int c
)
{
/* dummy function for now */
}
#define TAB_SPACE 4
#define CONSOLE_BG_COL 0xff
#define CONSOLE_FG_COL 0x00
static void *fb_mem = NULL;
static unsigned short maxCol;
static unsigned short maxRow;
static unsigned short bytes_per_pixel;
static unsigned int bytes_per_line;
static unsigned int bytes_per_char_line;
static unsigned char row;
static unsigned char column;
static unsigned int nLines;
static uint32_t fgx, bgx, eorx;
static int rpi_video_initialized;
static const int video_font_draw_table32[ 16 ][ 4 ] = {
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000, 0x00000000, 0x00ffffff },
{ 0x00000000, 0x00000000, 0x00ffffff, 0x00000000 },
{ 0x00000000, 0x00000000, 0x00ffffff, 0x00ffffff },
{ 0x00000000, 0x00ffffff, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00ffffff, 0x00000000, 0x00ffffff },
{ 0x00000000, 0x00ffffff, 0x00ffffff, 0x00000000 },
{ 0x00000000, 0x00ffffff, 0x00ffffff, 0x00ffffff },
{ 0x00ffffff, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00ffffff, 0x00000000, 0x00000000, 0x00ffffff },
{ 0x00ffffff, 0x00000000, 0x00ffffff, 0x00000000 },
{ 0x00ffffff, 0x00000000, 0x00ffffff, 0x00ffffff },
{ 0x00ffffff, 0x00ffffff, 0x00000000, 0x00000000 },
{ 0x00ffffff, 0x00ffffff, 0x00000000, 0x00ffffff },
{ 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00000000 },
{ 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff }
};
void
rpi_fb_outch( char c );
void
rpi_video_init( void );
static void scroll( void )
{
int i, j; /* Counters */
uint8_t *pt_scroll, *pt_bitmap; /* Pointers on the bit-map */
pt_bitmap = fb_mem;
j = 0;
pt_bitmap = pt_bitmap + j;
pt_scroll = pt_bitmap + bytes_per_char_line;
for ( i = j; i < maxRow - 1; i++ ) {
memcpy( pt_bitmap, pt_scroll, bytes_per_char_line );
pt_bitmap = pt_bitmap + bytes_per_char_line;
pt_scroll = pt_bitmap + bytes_per_char_line;
}
/*
* Blank characters are displayed on the last line.
*/
memset( pt_bitmap, CONSOLE_BG_COL, bytes_per_char_line );
}
static void doCRNL(
int cr,
int nl
)
{
if ( nl ) {
if ( ++row == maxRow ) {
scroll(); /* Scroll the screen now */
row = maxRow - 1;
}
nLines++;
}
if ( cr )
column = 0;
/* Move cursor on the next location */
if ( cr || nl ) {
wr_cursor( row, column );
}
}
static void advanceCursor( void )
{
if ( ++column == maxCol )
doCRNL( 1, 1 );
else
wr_cursor( row, column );
}
static void gotorc(
int r,
int c
)
{
column = c;
row = r;
wr_cursor( row, column );
}
static void video_drawchars(
int r,
int c,
unsigned char ch
)
{
if ( fb_mem == NULL ) {
return;
}
uint8_t *cdat, *dest, *dest0;
int rows, offset;
offset = r * bytes_per_char_line + c * bytes_per_pixel * RPI_FONT_WIDTH;
dest0 = fb_mem + offset;
/*
* only 32-bit per pixel format is supported for now
*/
cdat = rpi_font + ch * RPI_FONT_HEIGHT;
for ( rows = RPI_FONT_HEIGHT, dest = dest0;
rows--; dest += bytes_per_line ) {
uint8_t bits = *cdat++;
( (uint32_t *) dest )[ 0 ] =
( video_font_draw_table32
[ bits >> 4 ][ 0 ] & eorx ) ^ bgx;
( (uint32_t *) dest )[ 1 ] =
( video_font_draw_table32
[ bits >> 4 ][ 1 ] & eorx ) ^ bgx;
( (uint32_t *) dest )[ 2 ] =
( video_font_draw_table32
[ bits >> 4 ][ 2 ] & eorx ) ^ bgx;
( (uint32_t *) dest )[ 3 ] =
( video_font_draw_table32
[ bits >> 4 ][ 3 ] & eorx ) ^ bgx;
( (uint32_t *) dest )[ 4 ] =
( video_font_draw_table32
[ bits & 15 ][ 0 ] & eorx ) ^ bgx;
( (uint32_t *) dest )[ 5 ] =
( video_font_draw_table32
[ bits & 15 ][ 1 ] & eorx ) ^ bgx;
( (uint32_t *) dest )[ 6 ] =
( video_font_draw_table32
[ bits & 15 ][ 2 ] & eorx ) ^ bgx;
( (uint32_t *) dest )[ 7 ] =
( video_font_draw_table32
[ bits & 15 ][ 3 ] & eorx ) ^ bgx;
}
}
#define ESC ( (char) 27 )
/* erase current location without moving the cursor */
#define BLANK ( (char) 0x7f )
static void videoPutChar( char ch )
{
switch ( ch ) {
case '\b': {
if ( column )
column--;
/* Move cursor on the previous location */
wr_cursor( row, column );
return;
}
case '\t': {
int i;
i = TAB_SPACE - ( column & ( TAB_SPACE - 1 ) );
while ( i-- ) {
video_drawchars( row, column, ' ' );
column += 1;
if ( column >= maxCol ) {
doCRNL( 1, 1 );
return;
}
}
wr_cursor( row, column );
return;
}
case '\n': {
doCRNL( 0, 1 );
return;
}
case 7: { /* Bell code must be inserted here */
return;
}
case '\r': {
doCRNL( 1, 0 );
return;
}
case BLANK: {
video_drawchars( row, column, ' ' );
wr_cursor( row, column );
return;
}
default: {
// *pt_bitmap = (unsigned char)ch | attribute;
video_drawchars( row, column, ch );
advanceCursor();
return;
}
}
}
/* trivial state machine to handle escape sequences:
*
* ---------------------------------
* | |
* | |
* KEY: esc V [ DCABHKJ esc |
* STATE: 0 -----> 27 -----> '[' ----------> -1 -----
* ^\ \ \ \
* KEY: | \other \ other \ other \ other
* <-------------------------------------
*
* in state '-1', the DCABHKJ cases are handled
*
* (cursor motion and screen clearing)
*/
#define DONE ( -1 )
static int handleEscape(
int oldState,
char ch
)
{
int rval = 0;
int ro, co;
switch ( oldState ) {
case DONE: /* means the previous char terminated an ESC sequence... */
case 0:
if ( 27 == ch ) {
rval = 27; /* START of an ESC sequence */
}
break;
case 27:
if ( '[' == ch ) {
rval = ch; /* received ESC '[', so far */
} else {
/* dump suppressed 'ESC'; outch will append the char */
videoPutChar( ESC );
}
break;
case '[':
/* handle 'ESC' '[' sequences here */
ro = row;
co = column;
rval = DONE; /* done */
switch ( ch ) {
case 'D': /* left */
if ( co > 0 )
co--;
break;
case 'C': /* right */
if ( co < maxCol )
co++;
break;
case 'A': /* up */
if ( ro > 0 )
ro--;
break;
case 'B': /* down */
if ( ro < maxRow )
ro++;
break;
case 'H': /* home */
ro = co = 0;
break;
case 'K': /* clear to end of line */
while ( column < maxCol - 1 )
videoPutChar( ' ' );
videoPutChar( BLANK );
break;
case 'J': /* clear to end of screen */
while ( ( ( row < maxRow - 1 ) || ( column < maxCol - 1 ) ) )
videoPutChar( ' ' );
videoPutChar( BLANK );
break;
default:
videoPutChar( ESC );
videoPutChar( '[' );
/* DONT move the cursor */
ro = -1;
rval = 0;
break;
}
// /* reset cursor */
if ( ro >= 0 )
gotorc( ro, co );
default:
break;
}
return rval;
}
static void clear_screen( void )
{
int i, j;
for ( j = 0; j < maxRow; j++ ) {
for ( i = 0; i < maxCol; i++ ) {
videoPutChar( ' ' );
}
}
column = 0;
row = 0;
}
void rpi_fb_outch( char c )
{
static int escaped = 0;
if ( !( escaped = handleEscape( escaped, c ) ) ) {
if ( '\n' == c )
videoPutChar( '\r' );
videoPutChar( c );
}
}
void rpi_video_init( void )
{
struct fb_var_screeninfo fb_var_info;
struct fb_fix_screeninfo fb_fix_info;
rpi_get_var_screen_info( &fb_var_info );
rpi_get_fix_screen_info( &fb_fix_info );
maxCol = fb_var_info.xres / RPI_FONT_WIDTH;
maxRow = fb_var_info.yres / RPI_FONT_HEIGHT;
bytes_per_pixel = fb_var_info.bits_per_pixel / 8;
bytes_per_line = bytes_per_pixel * fb_var_info.xres;
bytes_per_char_line = RPI_FONT_HEIGHT * bytes_per_line;
fb_mem = RTEMS_DEVOLATILE( void *, fb_fix_info.smem_start );
column = 0;
row = 0;
nLines = 0;
fgx = ( CONSOLE_FG_COL << 24 ) |
( CONSOLE_FG_COL << 16 ) |
( CONSOLE_FG_COL << 8 ) |
CONSOLE_FG_COL;
bgx = ( CONSOLE_BG_COL << 24 ) |
( CONSOLE_BG_COL << 16 ) |
( CONSOLE_BG_COL << 8 ) |
CONSOLE_BG_COL;
eorx = fgx ^ bgx;
clear_screen();
rpi_video_initialized = 1;
}
/* for old DOS compatibility n-curses type of applications */
void gotoxy(
int x,
int y
);
int whereX( void );
int whereY( void );
void gotoxy(
int x,
int y
)
{
gotorc( y, x );
}
int whereX( void )
{
return row;
}
int whereY( void )
{
return column;
}

View File

@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <efi.h>
#include <rtems/fb.h>
int
efi_init_graphic_output(int);
void
efi_graphic_output_char(char);
/* to support RPi based character output to framebuffer.
The functions are declared here in open in order to show if they
should not be moved including whole character output to FB somewhere
into bsps/shared. */
void
rpi_get_var_screen_info(struct fb_var_screeninfo*);
void
rpi_get_fix_screen_info(struct fb_fix_screeninfo*);

View File

@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <efi.h>
void
efi_init_text_output(int);
void
efi_text_output_char(char);

View File

@@ -0,0 +1,417 @@
/* multiboot2.h - Multiboot 2 header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef _MULTIBOOT2_HEADER_H_
#define _MULTIBOOT2_HEADER_H_
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 32768
#define MULTIBOOT_HEADER_ALIGN 8
/* The magic field should contain this. */
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
/* This should be in %eax. */
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000008
/* Flags set in the 'flags' member of the multiboot header. */
#define MULTIBOOT_TAG_ALIGN 8
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
#define MULTIBOOT_TAG_TYPE_MODULE 3
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
#define MULTIBOOT_TAG_TYPE_MMAP 6
#define MULTIBOOT_TAG_TYPE_VBE 7
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
#define MULTIBOOT_TAG_TYPE_APM 10
#define MULTIBOOT_TAG_TYPE_EFI32 11
#define MULTIBOOT_TAG_TYPE_EFI64 12
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
#define MULTIBOOT_TAG_TYPE_NETWORK 16
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
#define MULTIBOOT_HEADER_TAG_END 0
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
#define MULTIBOOT_ARCHITECTURE_I386 0
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
#ifndef __ASSEMBLER__
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* ISA */
multiboot_uint32_t architecture;
/* Total header length. */
multiboot_uint32_t header_length;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
};
struct multiboot_header_tag
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_information_request
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t requests[0];
};
struct multiboot_header_tag_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
};
struct multiboot_header_tag_entry_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t entry_addr;
};
struct multiboot_header_tag_console_flags
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t console_flags;
};
struct multiboot_header_tag_framebuffer
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
struct multiboot_header_tag_module_align
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_relocatable
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t min_addr;
multiboot_uint32_t max_addr;
multiboot_uint32_t align;
multiboot_uint32_t preference;
};
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
multiboot_uint32_t zero;
};
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_tag
{
multiboot_uint32_t type;
multiboot_uint32_t size;
};
struct multiboot_tag_string
{
multiboot_uint32_t type;
multiboot_uint32_t size;
char string[0];
};
struct multiboot_tag_module
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
char cmdline[0];
};
struct multiboot_tag_basic_meminfo
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
};
struct multiboot_tag_bootdev
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t biosdev;
multiboot_uint32_t slice;
multiboot_uint32_t part;
};
struct multiboot_tag_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t entry_size;
multiboot_uint32_t entry_version;
struct multiboot_mmap_entry entries[0];
};
struct multiboot_vbe_info_block
{
multiboot_uint8_t external_specification[512];
};
struct multiboot_vbe_mode_info_block
{
multiboot_uint8_t external_specification[256];
};
struct multiboot_tag_vbe
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
struct multiboot_vbe_info_block vbe_control_info;
struct multiboot_vbe_mode_info_block vbe_mode_info;
};
struct multiboot_tag_framebuffer_common
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
multiboot_uint16_t reserved;
};
struct multiboot_tag_framebuffer
{
struct multiboot_tag_framebuffer_common common;
union
{
struct
{
multiboot_uint16_t framebuffer_palette_num_colors;
struct multiboot_color framebuffer_palette[0];
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
struct multiboot_tag_elf_sections
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t num;
multiboot_uint32_t entsize;
multiboot_uint32_t shndx;
char sections[0];
};
struct multiboot_tag_apm
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
struct multiboot_tag_efi32
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_smbios
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t major;
multiboot_uint8_t minor;
multiboot_uint8_t reserved[6];
multiboot_uint8_t tables[0];
};
struct multiboot_tag_old_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_new_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_network
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t dhcpack[0];
};
struct multiboot_tag_efi_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t descr_size;
multiboot_uint32_t descr_vers;
multiboot_uint8_t efi_mmap[0];
};
struct multiboot_tag_efi32_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_load_base_addr
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t load_base_addr;
};
#endif // __ASSEMBLER__
#endif // _MULTIBOOT2_HEADER_H_

View File

@@ -0,0 +1,38 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
void
process_multiboot2_info(void);
int
uefi_bootservices_running(void);
const char*
boot_args(void);
int
get_boot_arg_int_value(const char*, const char*, int*);

View File

@@ -28,9 +28,21 @@
#include <bsp/bootcard.h>
#include <libcpu/page.h>
#include <bsp/irq-generic.h>
#include <multiboot2impl.h>
#if defined(BSP_USE_EFI_BOOT_SERVICES) && !defined(BSP_MULTIBOOT_SUPPORT)
#error "RTEMS amd64efi BSP requires multiboot2 support!"
#endif
void bsp_start(void)
{
paging_init();
bsp_interrupt_initialize();
#ifdef BSP_MULTIBOOT_SUPPORT
process_multiboot2_info();
if (!uefi_bootservices_running()) {
#endif
paging_init();
bsp_interrupt_initialize();
#ifdef BSP_MULTIBOOT_SUPPORT
}
#endif
}

View File

@@ -0,0 +1,203 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <bsp/bootcard.h>
#include <efi.h>
#include <efilib.h>
#include <stdio.h>
extern Heap_Control *RTEMS_Malloc_Heap;
void bsp_memory_heap_extend(void);
extern EFI_BOOT_SERVICES *BS;
static UINT32 total_pages = 0;
static UINT32 allocated_pages = 0;
static UINT32 usable_pages = 0;
static EFI_PHYSICAL_ADDRESS physBuf;
static int error = 0;
static int extension_steps = 0;
#ifdef BSP_EFI_MMAP_PRINTOUT
static const char*
efi_memory_type(EFI_MEMORY_TYPE type);
#endif
void
efi_memory_heap_extend( void );
static UINT64
heap_size(void)
{
return RTEMS_Malloc_Heap->stats.size;
}
static UINT64
allocate_biggest_block( void )
{
UINT64 sz = 0;
EFI_MEMORY_DESCRIPTOR *map = 0, *p = 0;
UINTN key = 0, dsz = 0;
UINT32 dver = 0;
EFI_STATUS status = 0;
int i, ndesc = 0;
UINT64 to_alloc_pages = 0;
bool first_run = false;
if (total_pages == 0)
first_run = true;
// let's see available RAM
status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
if (status != EFI_BUFFER_TOO_SMALL) {
printf("EFI: Can't determine memory map size\n");
return 0;
}
map = malloc(sz);
if (map == NULL) {
printf("EFI: Can't allocate memory map backing\n");
return 0;
}
status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
if (EFI_ERROR(status)) {
printf("EFI: Can't read memory map\n");
free(map);
return 0;
}
ndesc = sz / dsz;
#ifdef BSP_EFI_MMAP_PRINTOUT
if (first_run)
printf("%23s %12s %8s\n", "Type", "Physical", "#Pages");
#endif
for (i = 0, p = map; i < ndesc;
i++, p = NextMemoryDescriptor(p, dsz)) {
if (first_run) {
#ifdef BSP_EFI_MMAP_PRINTOUT
printf("%23s %012jx %08jx\n", efi_memory_type(p->Type),
(uintmax_t)p->PhysicalStart, (uintmax_t)p->NumberOfPages);
#endif
if (p->Type != EfiReservedMemoryType)
total_pages = total_pages + p->NumberOfPages;
if (p->Type == EfiConventionalMemory) {
usable_pages = usable_pages + p->NumberOfPages;
}
}
if (p->Type == EfiConventionalMemory) {
if (to_alloc_pages < p->NumberOfPages)
to_alloc_pages = p->NumberOfPages;
}
}
status = ST->BootServices->AllocatePages(AllocateAnyPages, EfiLoaderData, to_alloc_pages, &physBuf );
if (EFI_ERROR(status)) {
/* on some UEFI implementations it is not possible to allocate biggest available block
for whatever reasons. In that case, let's go wild and attempt to allocate
half of it */
error++;
status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, (to_alloc_pages / 2), &physBuf );
if (EFI_ERROR(status)) {
printf("EFI can't allocate: %lu pages nor half of the amount.\n", to_alloc_pages);
free(map);
return 0;
}
else {
to_alloc_pages = to_alloc_pages / 2;
}
}
allocated_pages = allocated_pages + to_alloc_pages;
sz = to_alloc_pages * 4096;
uintptr_t es = 0;
es = _Heap_Extend( RTEMS_Malloc_Heap, (void *)physBuf, sz, 0 );
free(map);
return es;
}
void efi_memory_heap_extend( void )
{
int i;
UINT64 asz = 0;
UINT64 oldsz, newsz = 0;
oldsz = heap_size();
for (i = 0; i < 1024; i++) {
/* let's try 1k alloc attempts */
asz = allocate_biggest_block();
if (asz == 0)
break;
extension_steps++;
}
newsz = heap_size();
printf("EFI: Total memory: %u pages, %u megabytes\n", total_pages, (total_pages * 4 / 1024));
printf("EFI: Usable memory: %u pages, %u megabytes\n", usable_pages, (usable_pages * 4 / 1024));
printf("EFI: Allocated memory: %u pages, %u megabytes\n", allocated_pages, (allocated_pages * 4 / 1024));
printf("RTEMS: Heap extended in %u steps with %u steps failed.\n", extension_steps, error);
uint64_t s = newsz - oldsz;
printf("RTEMS: Heap extended by %lu pages, %lu megabytes\n", (s / 4096), ((s / 1024) / 1024));
}
#ifdef BSP_EFI_MMAP_PRINTOUT
static const char*
efi_memory_type(EFI_MEMORY_TYPE type)
{
switch (type) {
case EfiReservedMemoryType:
return "Reserved";
case EfiLoaderCode:
return "LoaderCode";
case EfiLoaderData:
return "LoaderData";
case EfiBootServicesCode:
return "BootServicesCode";
case EfiBootServicesData:
return "BootServicesData";
case EfiRuntimeServicesCode:
return "RuntimeServicesCode";
case EfiRuntimeServicesData:
return "RuntimeServicesData";
case EfiConventionalMemory:
return "ConventionalMemory";
case EfiUnusableMemory:
return "UnusableMemory";
case EfiACPIReclaimMemory:
return "ACPIReclaimMemory";
case EfiACPIMemoryNVS:
return "ACPIMemoryNVS";
case EfiMemoryMappedIO:
return "MemoryMappedIO";
case EfiMemoryMappedIOPortSpace:
return "MemoryMappedIOPortSpace";
case EfiPalCode:
return "PalCode";
case EfiPersistentMemory:
return "PersistentMemory";
default:
return "Unknown Type";
}
}
#endif

View File

@@ -28,13 +28,15 @@ RamBase = DEFINED(RamBase) ? RamBase :
/* XXX: Defaulting to 1GiB.
*/
RamSize = DEFINED(RamSize) ? RamSize :
DEFINED(_RamSize) ? _RamSize : 0x40000000;
/* DEFINED(_RamSize) ? _RamSize : 0x2000000;*/ /* 32MB */
DEFINED(_RamSize) ? _RamSize : 0x1000000; /* 16MB */
RamEnd = RamBase + RamSize;
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x00100000)); . = SEGMENT_START("text-segment", 0x00100000) + SIZEOF_HEADERS;
/* .multiboot2_header : { *(.multiboot2_header) }*/
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
@@ -88,6 +90,7 @@ SECTIONS
.plt.sec : { *(.plt.sec) }
.text :
{
KEEP (*(.multiboot2_header))
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
@@ -236,6 +239,7 @@ SECTIONS
{
*(SORT_BY_NAME (SORT_BY_ALIGNMENT (.noinit*)))
}
. = ALIGN(64);
.rtemsstack (NOLOAD) :
{
*(SORT(.rtemsstack.*))

View File

@@ -0,0 +1,174 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2023 Karel Gardas
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <inttypes.h>
#include <multiboot2.h>
#include <multiboot2impl.h>
#include <rtems/score/heap.h>
#include <efi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef BSP_MULTIBOOT_SUPPORT
#ifdef BSP_USE_EFI_BOOT_SERVICES
extern void
efi_console_initialize( void );
extern void
efi_memory_heap_extend(void);
extern EFI_HANDLE IH;
extern EFI_SYSTEM_TABLE *ST;
extern EFI_BOOT_SERVICES *BS;
extern EFI_RUNTIME_SERVICES *RS;
#endif
extern int _multiboot2_magic;
extern void* _multiboot2_info_ptr;
static int already_processed = 0;
#endif
static int bootservices_running = 0;
static char multiboot_boot_args[256];
extern Heap_Control *RTEMS_Malloc_Heap;
#ifdef BSP_MULTIBOOT_SUPPORT
void
process_multiboot2_info()
{
struct multiboot_tag *tag;
unsigned size;
#ifdef BSP_USE_EFI_BOOT_SERVICES
ST = 0;
RS = 0;
BS = 0;
#endif
if (already_processed)
return;
if (_multiboot2_magic == MULTIBOOT2_BOOTLOADER_MAGIC) {
if ((*(unsigned*)_multiboot2_info_ptr) & 7) {
printf("Multiboot2 info @ %p, unaligned mbi: 0x%x\n", _multiboot2_info_ptr, *(unsigned*)_multiboot2_info_ptr);
}
else {
size = *(unsigned*)_multiboot2_info_ptr;
printf("Multiboot2 info @ %p, size 0x%x\n", _multiboot2_info_ptr, size);
for (tag = (struct multiboot_tag *) (_multiboot2_info_ptr + 8);
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag + ((tag->size + 7) & ~7))) {
switch (tag->type) {
case MULTIBOOT_TAG_TYPE_CMDLINE:
printf("Multiboot2 booting arguments: `%s', args len: %d\n",
((struct multiboot_tag_string *) tag)->string,
((struct multiboot_tag_string *) tag)->size);
strncpy(multiboot_boot_args, ((struct multiboot_tag_string*)tag)->string, ((struct multiboot_tag_string*)tag)->size);
break;
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
printf("Multiboot2 loader name: `%s'\n", ((struct multiboot_tag_string *) tag)->string);
break;
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
struct multiboot_tag_framebuffer* fbtag = (struct multiboot_tag_framebuffer*)tag;
uint64_t fbbase = fbtag->common.framebuffer_addr;
printf("Multiboot2 framebuffer @ %p, resolution: %dx%d, pitch/bpp: %d/%d, type: %d\n",
(void*)fbbase, fbtag->common.framebuffer_width, fbtag->common.framebuffer_height,
fbtag->common.framebuffer_pitch, fbtag->common.framebuffer_bpp,
fbtag->common.framebuffer_type);
break;
#ifdef BSP_USE_EFI_BOOT_SERVICES
case MULTIBOOT_TAG_TYPE_EFI64:
printf("EFI64 system table @ 0x%llx\n", ((struct multiboot_tag_efi64 *) tag)->pointer);
ST = ((EFI_SYSTEM_TABLE*)((struct multiboot_tag_efi64 *) tag)->pointer);
BS = ST->BootServices;
RS = ST->RuntimeServices;
efi_console_initialize();
efi_memory_heap_extend();
break;
case MULTIBOOT_TAG_TYPE_EFI_BS:
printf("GRUB: EFI boot services running.\n");
bootservices_running = 1;
break;
case MULTIBOOT_TAG_TYPE_EFI64_IH:
printf("EFI: 64bit image handle: 0x%llx\n", ((struct multiboot_tag_efi64_ih *) tag)->pointer);
IH = (EFI_HANDLE)((struct multiboot_tag_efi64_ih *) tag)->pointer;
break;
#endif
}
}
}
}
else {
printf("So while not being booted by multiboot2, let's see what's in its magic then?: %dx\n", _multiboot2_magic);
}
}
#endif /* BSP_MULTIBOOT_SUPPORT */
int
uefi_bootservices_running()
{
return bootservices_running;
}
const char*
boot_args()
{
return multiboot_boot_args;
}
int
get_boot_arg_int_value(const char* boot_args, const char* arg, int* val)
{
int len_arg = strlen(arg);
int len_try = strlen(boot_args) - len_arg;
int len_bootargs = strlen(boot_args);
char num[10];
for (int i = 0; i < len_try; i++) {
if (strncmp(&(boot_args[i]), arg, len_arg) == 0) {
i = i + len_arg + 1;
for (int j = 0; j < 10; j++) {
if (boot_args[i + j] != ' ' && i + j < len_bootargs)
num[j] = boot_args[i + j];
else {
num[j] = 0;
*val = atoi(num);
return 0;
}
}
}
}
return -1;
}

View File

@@ -1,6 +1,7 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2023 Karel Gardas
* Copyright (C) 2018 embedded brains GmbH
*
* Redistribution and use in source and binary forms, with or without
@@ -25,6 +26,12 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bspopts.h>
#ifdef BSP_MULTIBOOT_SUPPORT
#include <multiboot2.h>
#endif
.text
.section .text._start,"ax",@progbits
.p2align 4,,15
@@ -36,6 +43,71 @@ _start:
subq $8, %rsp
.cfi_def_cfa_offset 16
xorl %edi, %edi
#ifdef BSP_MULTIBOOT_SUPPORT
mov %eax, _multiboot2_magic
mov %rbx, _multiboot2_info_ptr
#endif
movabsq $boot_card, %rax
call *%rax
.cfi_endproc
#ifdef BSP_MULTIBOOT_SUPPORT
multiboot2:
ret
_multiboot2_start:
jmp _start
.text
.section .multiboot2_header
.p2align 4,,15
multiboot2_header_start:
.long MULTIBOOT2_HEADER_MAGIC
.long MULTIBOOT_ARCHITECTURE_I386
.long multiboot2_header_end - multiboot2_header_start
.long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot2_header_end - multiboot2_header_start))
efi_bootservices_start:
.short MULTIBOOT_HEADER_TAG_EFI_BS
.short 0
.long efi_bootservices_end - efi_bootservices_start
efi_bootservices_end:
efi64_entry_start:
.short MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64
.short 0
.long efi64_entry_end - efi64_entry_start
.long _start /* directly copied from resulting ELF */
/* padding to 8 byte tags allignment */
.long 0
efi64_entry_end:
info_requests_start:
.short MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST
.short 0
.long info_requests_end - info_requests_start
.long MULTIBOOT_TAG_TYPE_EFI64
.long MULTIBOOT_TAG_TYPE_CMDLINE
#ifdef BSP_USE_EFI_BOOT_SERVICES
.long MULTIBOOT_TAG_TYPE_EFI_BS
#else
.long 0
#endif
/* padding to 8 byte tags allignment */
.long 0
info_requests_end:
/* header end*/
.short MULTIBOOT_HEADER_TAG_END
.short 0
.long 8
multiboot2_header_end:
.data
.global _multiboot2_magic
_multiboot2_magic:
.long 0
.data
.global _multiboot2_info_ptr
_multiboot2_info_ptr:
.quad 0
#endif

View File

@@ -0,0 +1,17 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
build-type: objects
cflags: []
copyrights:
- Copyright (C) 2023 Karel Gardas
cppflags: []
cxxflags: []
enabled-by: true
includes:
- bsps/shared/freebsd/stand/efi/include
- bsps/shared/freebsd/stand/efi/include/amd64
install: []
links: []
source:
- bsps/shared/freebsd/stand/efi/libefi/libefi.c
- bsps/shared/freebsd/stand/efi/libefi/wchar.c
type: build

View File

@@ -0,0 +1,18 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-boolean: null
- env-assign: null
- define-condition: null
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: true
description: |
Enable use of EFI boot services.
enabled-by: true
format: '{}'
links: []
name: BSP_USE_EFI_BOOT_SERVICES
type: build

View File

@@ -0,0 +1,29 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-string: null
- define: null
- script: |
kinds = ["TEXT", "GRAPHIC", "BOTH", "AUTO"]
if value not in kinds:
conf.fatal("Preferred EFI console '{}' is not one of {}".format(value, kinds))
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: AUTO
description: |
Select preferred EFI console. Possible values are TEXT, GRAPHIC, BOTH and AUTO. The TEXT here will instruct RTEMS to use EFI simple text output protocol. By default
EFI also forwards such text output to configured serial port. Details depends on the target platform EFI configuration.
The GRAPHIC instructs RTEMS to use EFI graphics output protocol. Advantage of it
in comparison with TEXT is that it is available also in the time when boot services
are already finished. BOTH tells RTEMS to mirror its output to both TEXT and GRAPHIC. This only
applies to platforms where both options are supported. The option which is not supported
on target platform is ignored in the RTEMS runtime and only available option is used. Finally AUTO tells RTEMS to use output console
preferred by the target platform configuration. In case RTEMS is not able to retrieve EFI console control protocol interface, then BOTH
is used instead of AUTO.
enabled-by: true
format: '{}'
links: []
name: BSP_EFI_CONSOLE_KIND
type: build

View File

@@ -0,0 +1,27 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-string: null
- script: |
kinds = ["SERIAL", "BUFFER"]
if value not in kinds:
conf.fatal("Preferred EFI early console '{}' is not one of {}".format(value, kinds))
conf.define("BUFFER", "1", False)
conf.define("SERIAL", "2", False)
- define-unquoted: null
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: BUFFER
description: |
Select preferred EFI early printout console. Possible values here
are SERIAL and BUFFER. In case of SERIAL, the tty0/com1 will be used
for early printout. In case of BUFFER, all prints will be buffered
and once real EFI console is initialized, then whole buffer will be
copied to it.
enabled-by: true
format: '{}'
links: []
name: BSP_EFI_EARLY_CONSOLE_KIND
type: build

View File

@@ -0,0 +1,20 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-string: null
- define: null
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: AUTO
description: |
Define EFI graphics output protocol mode value. Use MAX to select maximum
available mode or AUTO to allow automatic selection based on the platform
preference. Otherwise use positive integer number to select desired graphics
protocol mode which you can get from graphics protocol mode list.
enabled-by: true
format: '{}'
links: []
name: BSP_EFI_GRAPHICS_OUTPUT_MODE_VALUE
type: build

View File

@@ -0,0 +1,18 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-boolean: null
- env-assign: null
- define-condition: null
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: false
description: |
Print EFI memory map on boot.
enabled-by: true
format: '{}'
links: []
name: BSP_EFI_MMAP_PRINTOUT
type: build

View File

@@ -0,0 +1,21 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-string: null
- define: null
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: AUTO
description: |
Define EFI simple text output protocol mode value. Use MAX to select maximum
available mode or AUTO to allow automatic selection based on the platform
preference. Otherwise use positive integer number to select desired simple
text output protocol mode which you can get from simple text protocol mode
list.
enabled-by: true
format: '{}'
links: []
name: BSP_EFI_SIMPLE_TEXT_OUTPUT_MODE_VALUE
type: build

View File

@@ -0,0 +1,18 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-boolean: null
- env-assign: null
- define-condition: null
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: true
description: |
Enable multiboot2 support in the startup assembly.
enabled-by: true
format: '{}'
links: []
name: BSP_MULTIBOOT_SUPPORT
type: build

View File

@@ -0,0 +1,84 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
arch: x86_64
bsp: amd64efi
build-type: bsp
cflags: []
copyrights:
- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
cppflags: []
enabled-by: true
family: amd64
includes:
- bsps/shared/freebsd/stand/efi/include
- bsps/shared/freebsd/stand/efi/include/amd64
install:
- destination: ${BSP_INCLUDEDIR}
source:
- bsps/x86_64/amd64/include/apic.h
- bsps/x86_64/amd64/include/bsp.h
- bsps/x86_64/amd64/include/clock.h
- bsps/x86_64/amd64/include/pic.h
- bsps/x86_64/amd64/include/start.h
- destination: ${BSP_LIBDIR}
source:
- bsps/x86_64/amd64/start/linkcmds
links:
- role: build-dependency
uid: ../../obj
- role: build-dependency
uid: ../../objirq
- role: build-dependency
uid: ../../objmem
- role: build-dependency
uid: ../../opto2
- role: build-dependency
uid: efiabi
- role: build-dependency
uid: start
- role: build-dependency
uid: ../grp
- role: build-dependency
uid: ../../optmultiboot
- role: build-dependency
uid: ../../opteficonsole
- role: build-dependency
uid: ../../optefiearlyconsole
- role: build-dependency
uid: ../../optefistom
- role: build-dependency
uid: ../../optefigopm
- role: build-dependency
uid: ../../optefimmapprint
- role: build-dependency
uid: ../../optefibs
- role: build-dependency
uid: ../../bspopts
- role: build-dependency
uid: optldpagesize
- role: build-dependency
uid: ../../objefi
source:
- bsps/shared/cache/nocache.c
- bsps/shared/dev/btimer/btimer-cpucounter.c
- bsps/shared/dev/getentropy/getentropy-cpucounter.c
- bsps/shared/dev/serial/console-termios-init.c
- bsps/shared/dev/serial/console-termios.c
- bsps/shared/irq/irq-default-handler.c
- bsps/shared/start/bspfatal-default.c
- bsps/shared/start/bspreset-empty.c
- bsps/shared/start/gettargethash-default.c
- bsps/shared/start/sbrk.c
- bsps/x86_64/amd64/clock/eficlock.c
- bsps/x86_64/amd64/console/eficonsole.c
- bsps/x86_64/amd64/console/efistop.c
- bsps/x86_64/amd64/console/efigop.c
- bsps/x86_64/amd64/console/outch.c
- bsps/x86_64/amd64/console/console.c
- bsps/x86_64/amd64/interrupts/idt.c
- bsps/x86_64/amd64/interrupts/isr_handler.S
- bsps/x86_64/amd64/interrupts/pic.c
- bsps/x86_64/amd64/start/bspstart.c
- bsps/x86_64/amd64/start/multiboot2.c
- bsps/x86_64/amd64/start/efimem.c
- bsps/x86_64/amd64/start/page.c
type: build

View File

@@ -0,0 +1,23 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-string: null
- split: null
- env-append: null
build-type: option
copyrights:
- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
default:
- enabled-by: true
value:
- -fshort-wchar
- -maccumulate-outgoing-args
- -fno-stack-protector
- -fno-stack-check
- -mno-red-zone
- -mcmodel=large
description: |
ABI flags
enabled-by: true
links: []
name: ABI_FLAGS
type: build

View File

@@ -0,0 +1,25 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
actions:
- get-integer: null
- assert-uint32: null
- env-assign: null
- set-value: -Wl,-z,max-page-size=${LD_MAX_PAGE_SIZE:#010x}
- substitute: null
- env-append: LDFLAGS
- env-append: PKGCONFIG_LDFLAGS
build-type: option
copyrights:
- Copyright (C) 2023 Karel Gardas
default:
- enabled-by: true
value: 4096
description: |
Set the value of max-page-size parameter for the GNU linker.
By default on x86_64 the linker is using 2MB page size which is
too big for creating correctly formed and later recognized multiboot2
binaries. Default value 4k used here is working well for the purpose.
enabled-by: true
format: '{:#010x}'
links: []
name: LD_MAX_PAGE_SIZE
type: build