Skip to content
This repository has been archived by the owner on May 18, 2024. It is now read-only.

UEFI Support #30

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
*~
*.swp
2048*
*.o
*.core
hello.efi
hello.so
tags
40 changes: 40 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)

C_FILES := $(wildcard *.c)
MERGE_FILE := merge_std.c
FILTERED_C_FILES := $(filter-out gfx%.c merge%.c highscore%.c, $(C_FILES)) $(MERGE_FILE) gfx_uefi.c highscore_uefi.c

OBJS = $(FILTERED_C_FILES:.c=.o)
TARGET = 2048.efi

EFIINC = /usr/include/efi
EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
LIB = /usr/lib
EFILIB = /usr/lib
EFI_CRT_OBJS = $(EFILIB)/crt0-efi-$(ARCH).o
EFI_LDS = $(EFILIB)/elf_$(ARCH)_efi.lds

#CFLAGS = -nostdinc $(EFIINCS) -fno-stack-protector -fpic
CFLAGS = $(EFIINCS) -fno-stack-protector -fpic \
-fshort-wchar -mno-red-zone -Wall
CFLAGS += -DINVERT_COLORS -O2

ifeq ($(ARCH),x86_64)
CFLAGS += -DEFI_FUNCTION_WRAPPER
endif

LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \
-Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS)

all: $(TARGET)

2048.so: $(OBJS)
ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi

%.efi: %.so
objcopy -j .text -j .sdata -j .data -j .dynamic \
-j .dynsym -j .rel -j .rela -j .reloc \
--target=efi-app-$(ARCH) $^ $@

clean:
rm -f *.o 2048.efi 2048.so
68 changes: 68 additions & 0 deletions src/Rand.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*-
* Portions Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
*/
//__FBSDID("$FreeBSD: src/lib/libc/stdlib/rand.c,v 1.17.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $");
//#include <LibConfig.h>
#include <efi.h>

#include <stdlib.h>

static UINT32 next = 1;

/** Compute a pseudo-random number.
*
* Compute x = (7^5 * x) mod (2^31 - 1)
* without overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
**/
int
rand()
{
INT32 hi, lo, x;

/* Can't be initialized with 0, so use another value. */
if (next == 0)
next = 123459876;
hi = next / 127773;
lo = next % 127773;
x = 16807 * lo - 2836 * hi;
if (x < 0)
x += 0x7fffffff;
return ((next = x) % ((UINT32)RAND_MAX + 1));
}

void
srand(unsigned int seed)
{
next = (UINT32)seed;
}
26 changes: 16 additions & 10 deletions src/engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "engine.h"
#include "highscore.h"

#include <efi.h>
#include <efilib.h>

/* Utilize block counter to improve some of the functions so they can run
* quicker */

Expand Down Expand Up @@ -213,23 +216,26 @@ static int digits_ceiling(unsigned int n)
/* Return NULL if we couldn't allocate space for the gamestate. initializating the
* gamestate will parse the options internally, so any caller should pass argc and argv
* through this function */
struct gamestate* gamestate_init(int argc, char **argv)
struct gamestate* gamestate_init(int argc, CHAR16 **argv)
{
EFI_TIME Time;

struct gameoptions *opt = gameoptions_default();
if (!opt) return NULL;

if (argc != 0) parse_options(opt, argc, argv);

srand(time(NULL));
uefi_call_wrapper(ST->RuntimeServices->GetTime, 2, &Time, NULL);
srand(Time.Day*24*3600+Time.Hour*3600+Time.Minute*60+Time.Second+Time.Nanosecond);

struct gamestate *g = malloc(sizeof(struct gamestate));
struct gamestate *g = AllocatePool(sizeof(struct gamestate));
if (!g) goto gamestate_alloc_fail;
g->gridsize = opt->grid_width * opt->grid_height;

g->grid_data_ptr = calloc(g->gridsize, sizeof(int));
g->grid_data_ptr = AllocateZeroPool(g->gridsize*sizeof(int));
if (!g->grid_data_ptr) goto grid_data_alloc_fail;

g->grid = malloc(opt->grid_height * sizeof(int*));
g->grid = AllocatePool(opt->grid_height * sizeof(int*));
if (!g->grid) goto grid_alloc_fail;

/* Switch to two allocation version */
Expand Down Expand Up @@ -260,9 +266,9 @@ struct gamestate* gamestate_init(int argc, char **argv)
return g;

grid_alloc_fail:
free(g->grid_data_ptr);
FreePool(g->grid_data_ptr);
grid_data_alloc_fail:
free(g);
FreePool(g);
gamestate_alloc_fail:
return NULL;
}
Expand All @@ -285,7 +291,7 @@ void gamestate_clear(struct gamestate *g)
{
highscore_save(g);
gameoptions_destroy(g->opts);
free(g->grid_data_ptr); /* Free grid data */
free(g->grid); /* Free pointers to data slots */
free(g);
FreePool(g->grid_data_ptr); /* Free grid data */
FreePool(g->grid); /* Free pointers to data slots */
FreePool(g);
}
2 changes: 1 addition & 1 deletion src/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ int gamestate_end_condition(struct gamestate*);
void gamestate_new_block(struct gamestate*);
int gamestate_tick(struct gfx_state*, struct gamestate*, int, void (*callback)(struct gfx_state*, struct gamestate*));
void gamestate_clear(struct gamestate*);
struct gamestate* gamestate_init(int argc, char **argv);
struct gamestate* gamestate_init(int argc, CHAR16 **argv);

#endif
193 changes: 193 additions & 0 deletions src/gfx_uefi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#include "gfx.h"
#include "merge.h"

#include <efi.h>
#include <efilib.h>

#define NUMBER_OF_COLORS 7

#define iterate(n, expression)\
do {\
int i;\
for (i = 0; i < n; ++i) { expression; }\
} while (0)

static void print_pos(INTN Row, INTN Column, CHAR16 *str)
{
uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, Column, Row);
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, str);
}

struct gfx_state {
INTN window_height, window_width;
};

INTN uefi_color_array[] = {
#ifdef INVERT_COLORS
EFI_BLACK | EFI_BACKGROUND_RED,
EFI_BLACK | EFI_BACKGROUND_GREEN,
EFI_BLACK | EFI_BACKGROUND_BROWN,
EFI_BLACK | EFI_BACKGROUND_BLUE,
EFI_BLACK | EFI_BACKGROUND_MAGENTA,
EFI_BLACK | EFI_BACKGROUND_CYAN,
EFI_BLACK | EFI_BACKGROUND_LIGHTGRAY,
#else
EFI_RED | EFI_BACKGROUND_BLACK,
EFI_GREEN | EFI_BACKGROUND_BLACK,
EFI_YELLOW | EFI_BACKGROUND_BLACK,
EFI_BLUE | EFI_BACKGROUND_BLACK,
EFI_MAGENTA | EFI_BACKGROUND_BLACK,
EFI_CYAN | EFI_BACKGROUND_BLACK,
EFI_WHITE | EFI_BACKGROUND_BLACK,
#endif
};

struct gfx_state* gfx_init(struct gamestate *g)
{
struct gfx_state *s = AllocatePool(sizeof(struct gfx_state));
if (!s) return NULL;

uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &s->window_width, &s->window_height);
uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0);
uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, false);

s->window_height = g->opts->grid_height * (g->print_width + 2) + 3;
s->window_width = g->opts->grid_width * (g->print_width + 2) + 1;

return s;
}

void gfx_draw(struct gfx_state *s, struct gamestate *g)
{
if (g->score_last) {
uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0);
Print(L"Score: %ld (+%ld) \n", g->score, g->score_last);
} else {
uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, 0);
Print(L"Score: %ld \n", g->score);
}

if (g->score >= g->score_high)
g->score_high = g->score;

Print(L" Hi: %ld\n", g->score_high);

//wattron(s->window, A_DIM);
Print(L"%c", BOXDRAW_DOWN_RIGHT);
iterate(g->opts->grid_width * (g->print_width + 2) + 1 - 2, Print(L"%c", (i+g->print_width+3) % (g->print_width+2) ? BOXDRAW_HORIZONTAL : BOXDRAW_DOWN_HORIZONTAL));
Print(L"%c", BOXDRAW_DOWN_LEFT);
//wattroff(s->window, A_DIM);

int x, y,
xpos = 0,
ypos = 3;

for (y = 0; y < g->opts->grid_height; ++y, ++ypos, xpos = 0) {
//wattron(s->window, A_DIM);
print_pos(ypos, xpos++, L"");
Print(L"%c", BOXDRAW_VERTICAL);
//wattroff(s->window, A_DIM);

for (x = 0; x < g->opts->grid_width; ++x) {
if (g->grid[x][y]) {
if (g->opts->enable_color) {
UINTN attr = uefi_color_array[g->grid[x][y] % NUMBER_OF_COLORS];
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, attr);
}
uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, xpos, ypos);
Print(L"%-*ld", g->print_width, merge_value(g->grid[x][y]));
print_pos(ypos, xpos + g->print_width, L" ");
if (g->opts->enable_color) {
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
}

//wattron(s->window, A_DIM);
print_pos(ypos, xpos + g->print_width + 1, L"");
Print(L"%c", BOXDRAW_VERTICAL);
//wattroff(s->window, A_DIM);
}
else {
//wattron(s->window, A_DIM);
iterate(g->print_width + 1, Print(L" "));
Print(L"%c", BOXDRAW_VERTICAL);
//wattroff(s->window, A_DIM);
}

xpos += (g->print_width + 2);
}
}

Print(L"\n");
//wattron(s->window, A_DIM);
Print(L"%c", BOXDRAW_UP_RIGHT);
iterate(g->opts->grid_width * (g->print_width + 2) + 1 - 2, Print(L"%c", (i+g->print_width+3) % (g->print_width+2) ? BOXDRAW_HORIZONTAL : BOXDRAW_UP_HORIZONTAL));
Print(L"%c", BOXDRAW_UP_LEFT);
//wattroff(s->window, A_DIM);
Print(L"\n");
}

int gfx_getch(struct gfx_state *s)
{
EFI_INPUT_KEY Key;

Pause();
uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &Key);

/* Flush buffer */
//nodelay(s->window, TRUE);
//while (wgetch(s->window) != ERR);
//nodelay(s->window, FALSE);

switch (Key.ScanCode)
{
case SCAN_UP:
return INPUT_UP;
break;
case SCAN_DOWN:
return INPUT_DOWN;
break;
case SCAN_RIGHT:
return INPUT_RIGHT;
break;
case SCAN_LEFT:
return INPUT_LEFT;
break;

default:
return Key.UnicodeChar;
break;

}
}

#define EFI_TIMER_PERIOD_MILLISECONDS(Milliseconds) MultU64x32((UINT64)(Milliseconds), 10000)

void gfx_sleep(int ms)
{
EFI_STATUS Status;
EFI_EVENT TimerEvent;
UINTN Index;

Status = uefi_call_wrapper(BS->CreateEvent, 5, EFI_EVENT_TIMER, 0, NULL, NULL, &TimerEvent);
if(EFI_ERROR(Status)) {
return;
}

Status = uefi_call_wrapper(BS->SetTimer, 3, TimerEvent, TimerRelative, EFI_TIMER_PERIOD_MILLISECONDS(ms));
if(EFI_ERROR(Status)) {
return;
}

Status = uefi_call_wrapper(BS->WaitForEvent, 3, 1, &TimerEvent, &Index);
if(EFI_ERROR(Status)) {
return;
}
Status = uefi_call_wrapper(BS->CloseEvent, TimerEvent);
}

void gfx_destroy(struct gfx_state *s)
{
FreePool(s);
uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, true);
}
Loading