Commit 061416ec authored by Simonas's avatar Simonas

Implement some graphics

Namely:
1. We choose a display mode for 1080p graphics and set it;
2. Draw the lithuanian flag to see if the framebuffer is configured properly. This also doubles as
our workload before shutting down in place of long loop we had previously.
parent 246b0e8d
ARCH = x86_64
ARCH = x86_64
OBJS = src/main.o
HEADERS = src/kernel.h
OBJS = src/main.o src/graphics.o
EFIINC = /usr/include/efi
EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
EFI_CRT_OBJS = /usr/lib/crt0-efi-$(ARCH).o
EFI_LDS = /usr/lib/elf_$(ARCH)_efi.lds
OVMF = /usr/share/ovmf/ovmf_x64.bin
QEMU_OPTS = -enable-kvm -m 64
EFIINC = /usr/include/efi
EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
EFI_CRT_OBJS = /usr/lib/crt0-efi-$(ARCH).o
EFI_LDS = /usr/lib/elf_$(ARCH)_efi.lds
OVMF = /usr/share/ovmf/ovmf_x64.bin
QEMU_OPTS = -enable-kvm -m 64 -device VGA
CFLAGS = $(EFIINCS) -xc -std=c11 -fno-stack-protector -fpic -fshort-wchar -mno-red-zone \
-Wall -Wno-incompatible-library-redeclaration -O2
CFLAGS = $(EFIINCS) -xc -std=c11 -fno-stack-protector -fpic -fshort-wchar -mno-red-zone -Wall
ifeq ($(ARCH),x86_64)
CFLAGS += -DEFI_FUNCTION_WRAPPER
endif
LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L /usr/lib $(EFI_CRT_OBJS)
LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L /usr/lib $(EFI_CRT_OBJS)
all: image.img
......@@ -38,3 +41,6 @@ huehuehuehuehue.so: $(OBJS)
%.efi: %.so
objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc --target=efi-app-$(ARCH) $^ $@
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $@ $<
#include <efi.h>
#include <efilib.h>
#include <efiprot.h>
#include "kernel.h"
struct graphics_info graphics_info;
EFI_STATUS
select_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *graphics, OUT UINT32 *mode);
EFI_STATUS
init_graphics(EFI_GRAPHICS_OUTPUT_PROTOCOL *graphics)
{
UINT32 new_mode;
EFI_STATUS status = select_mode(graphics, &new_mode);
ASSERT_EFI_STATUS(status, L"init_graphics select_mode");
status = uefi_call_wrapper(graphics->SetMode, 2, graphics, new_mode);
ASSERT_EFI_STATUS(status, L"init_graphics SetMode");
graphics_info.protocol = graphics;
graphics_info.buffer_base = (void*)graphics->Mode->FrameBufferBase;
graphics_info.buffer_size = graphics->Mode->FrameBufferSize;
return EFI_SUCCESS;
}
EFI_STATUS
select_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *graphics, OUT UINT32 *mode)
{
*mode = graphics->Mode->Mode;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION most_appropriate_info;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
UINTN size;
// Initialize info of current mode
EFI_STATUS status = uefi_call_wrapper(graphics->QueryMode, 4,
graphics, *mode, &size, &info);
ASSERT_EFI_STATUS(status, L"select_mode");
most_appropriate_info = *info;
// Look for a better mode
for(UINT32 i = 0; i < graphics->Mode->MaxMode; i += 1) {
// Find out the parameters of the mode we’re looking at
EFI_STATUS status = uefi_call_wrapper(graphics->QueryMode, 4,
graphics, i, &size, &info);
ASSERT_EFI_STATUS(status, L"select_mode");
#ifdef DEBUG
Print(L"Option #%d: w: %d, h: %d, pixel format: %d\n",
i, info->HorizontalResolution, info->VerticalResolution, info->PixelFormat);
#endif
// We only accept RGB or BGR 8 bit colorspaces.
if(info->PixelFormat != PixelRedGreenBlueReserved8BitPerColor &&
info->PixelFormat != PixelBlueGreenRedReserved8BitPerColor) {
continue;
}
// If either of resolutions exceed appropriate w/h we cannot use the mode.
if(info->HorizontalResolution > GRAPHICS_MOST_APPROPRIATE_W ||
info->VerticalResolution > GRAPHICS_MOST_APPROPRIATE_H) {
continue;
}
// Obviously the best mode!
if(info->VerticalResolution == GRAPHICS_MOST_APPROPRIATE_H &&
info->HorizontalResolution == GRAPHICS_MOST_APPROPRIATE_W) {
most_appropriate_info = *info;
*mode = i;
break;
}
// Otherwise we have an arbitrary preferece to get as much vertical resolution as possible.
if(info->VerticalResolution > most_appropriate_info.VerticalResolution) {
most_appropriate_info = *info;
*mode = i;
}
}
graphics_info.output_mode = most_appropriate_info;
#ifdef DEBUG
Print(L"Option #%d selected: w: %d, h: %d, pixel format: %d\n",
*mode,
most_appropriate_info.HorizontalResolution, most_appropriate_info.VerticalResolution,
most_appropriate_info.PixelFormat);
#endif
return EFI_SUCCESS;
}
void set_pixel(int w, int h, uint32_t rgb) {
w *= 4;
h *= 4;
int32_t *addr = graphics_info.buffer_base + w + h * graphics_info.output_mode.PixelsPerScanLine;
*addr = rgb | 0xff000000;
}
#pragma once
#include <efi.h>
#include <efilib.h>
#include <efiprot.h>
#include <stddef.h>
struct boot_state {
UINTN memory_map_size;
EFI_MEMORY_DESCRIPTOR *memory_map;
UINTN map_key;
UINTN descriptor_size;
UINT32 descriptor_version;
};
extern struct boot_state boot_state;
struct graphics_info {
EFI_GRAPHICS_OUTPUT_PROTOCOL *protocol;
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION output_mode;
void* buffer_base;
size_t buffer_size;
};
extern struct graphics_info graphics_info;
#define GRAPHICS_MOST_APPROPRIATE_H 1080
#define GRAPHICS_MOST_APPROPRIATE_W 1920
EFI_STATUS init_graphics(EFI_GRAPHICS_OUTPUT_PROTOCOL *graphics);
void set_pixel(int w, int h, uint32_t rgba);
#define ASSERT_EFI_STATUS(x, n) {if(EFI_ERROR((x))) { Print(n": %r\n", x); return x; }}
#include <efi.h>
#include <efilib.h>
#include <efiprot.h>
struct boot_state {
UINTN memory_map_size;
EFI_MEMORY_DESCRIPTOR *memory_map;
UINTN map_key;
UINTN descriptor_size;
UINT32 descriptor_version;
};
#include "kernel.h"
struct boot_state boot_state;
EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS status;
InitializeLib(ImageHandle, SystemTable);
uefi_call_wrapper(SystemTable->ConOut->ClearScreen, 1, SystemTable->ConOut);
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
L"HueHueHueHueHue is here!\r\n");
struct boot_state state;
// Figure out the size of memory map.
state.memory_map = LibMemoryMap(&state.memory_map_size, &state.map_key, &state.descriptor_size,
&state.descriptor_version);
uefi_call_wrapper(SystemTable->ConOut->OutputString, 2, SystemTable->ConOut,
L"Exiting BootServices\r\n");
uefi_call_wrapper(SystemTable->BootServices->ExitBootServices, 2, ImageHandle, state.map_key);
boot_state.memory_map = LibMemoryMap(&boot_state.memory_map_size, &boot_state.map_key,
&boot_state.descriptor_size,
&boot_state.descriptor_version);
uefi_call_wrapper(SystemTable->RuntimeServices->SetVirtualAddressMap, 4,
state.memory_map_size, state.descriptor_size, state.descriptor_version,
state.memory_map);
for(int i = 0; i < 1000000000; i++); // some work to do
EFI_GRAPHICS_OUTPUT_PROTOCOL *graphics;
EFI_GUID graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
status = uefi_call_wrapper(SystemTable->BootServices->LocateProtocol, 3,
&graphics_proto, NULL, &graphics);
ASSERT_EFI_STATUS(status, L"LocateProtocol Graphics");
status = init_graphics(graphics);
if(status != EFI_SUCCESS) return status;
uefi_call_wrapper(SystemTable->BootServices->ExitBootServices, 2,
ImageHandle, boot_state.map_key);
uefi_call_wrapper(SystemTable->RuntimeServices->SetVirtualAddressMap, 4,
boot_state.memory_map_size, boot_state.descriptor_size,
boot_state.descriptor_version, boot_state.memory_map);
// Some work, blends in the lithuanian flag
for(uint8_t o = 0; o <= 100; o += 1) {
for(int x = 0; x < 1920; x += 1) {
for(int y = 0; y < 360; y += 1) {
uint32_t r = (0xfd * o / 100 ) << 16;
uint32_t g = (0xb9 * o / 100 ) << 8;
uint32_t b = (0x13 * o / 100 );
set_pixel(x, y, r | g | b);
}
}
for(int x = 0; x < 1920; x += 1) {
for(int y = 360; y < 720; y += 1) {
uint32_t g = (0x6a * o / 100) << 8;
uint32_t b = (0x44 * o / 100);
set_pixel(x, y, g | b);
}
}
for(int x = 0; x < 1920; x += 1) {
for(int y = 720; y < 1080; y += 1) {
uint32_t r = (0xc1 * o / 100) << 16;
uint32_t g = (0x27 * o / 100) << 8;
uint32_t b = (0x2d * o / 100);
set_pixel(x, y, r | g | b);
}
}
}
// Once we’re done we poweroff the machine.
uefi_call_wrapper(SystemTable->RuntimeServices->ResetSystem, 4,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment