Skip to content

Commit

Permalink
Unicycle application UEFI bootloader
Browse files Browse the repository at this point in the history
Add a UFI bootloader that allows to load Unicycle applications either
from bootable device (like USB sticks) or over the network using TFTP
protocol.
  • Loading branch information
anatol committed Apr 27, 2019
0 parents commit 0b0eeaf
Show file tree
Hide file tree
Showing 77 changed files with 11,298 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
IndentWidth: 4
ColumnLimit: 140
AlignEscapedNewlinesLeft: true
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
bootloader.efi
bootloader.so
*.o
boot.img
27 changes: 27 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Copyright 2018 Anatol Pomazau. All rights reserved.
Copyright 2017 The Fuchsia Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Google Inc. 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 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.
63 changes: 63 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
ARCH = x86_64

LD=$(TOOLCHAIN_PATH)ld
NM=$(TOOLCHAIN_PATH)nm
OBJCOPY=$(TOOLCHAIN_PATH)objcopy
CC?=$(TOOLCHAIN_PATH)gcc

CFLAGS = -Ixefi -Iinclude -flto -W -Wall -Wextra -O3 -fno-stack-protector -fno-math-errno -fno-trapping-math -fno-common -fshort-wchar -nostdlib -ffreestanding -std=c11 -m64
ifeq ($(ARCH),x86_64)
CFLAGS += -mno-red-zone
endif

EFI_SECTIONS = -j .text -j .data -j .reloc

ifeq ($(CC),clang)
CFLAGS += --target=$(ARCH)-windows-msvc
LDFLAGS += /subsystem:efi_application /entry:efi_main
else
CFLAGS += -fPIE
LDFLAGS += -Wl,-T xefi/efi-x86-64.lds -Wl,--gc-sections
endif

TARGET = bootloader.efi

OBJS = bootloader.o \
config.o \
netboot.o \
loadelf.o \
bootinfo.o \
framebuffer.o \
inet.o \
inet6.o \
netifc.o \
device_id.o \
tftp/tftp.o \
xefi/xefi.o \
xefi/guids.o \
xefi/printf.o \
xefi/console-printf.o \
xefi/ctype.o \
xefi/string.o \
xefi/strings.o \
xefi/stdlib.o \
xefi/loadfile.o

all: $(TARGET)

ifeq ($(CC),clang)

bootloader.efi: $(OBJS)
lld-link $(LDFLAGS) $^ /out:$@
if [ "`$(NM) $< | grep ' U '`" != "" ]; then echo "error: $<: undefined symbols"; $(NM) $< | grep ' U '; rm $<; exit 1; fi

else

bootloader.so: $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@

%.efi: %.so
$(OBJCOPY) $(EFI_SECTIONS) --target=efi-app-$(ARCH) $^ $@
if [ "`$(NM) $< | grep ' U '`" != "" ]; then echo "error: $<: undefined symbols"; $(NM) $< | grep ' U '; rm $<; exit 1; fi

endif
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# UEFI-based bootloader for Unicycle applications

UEFI bootloader that allows to load Unicycle application directly, without any support from operating system like
Linux. This bootloader implements [Uniboot](https://github.com/libunicycle/uniboot-spec) protocol on top of UEFI specification.

The bootloader supports booting from the same bootable device where bootloader.efi is located or loading from network using TFTP protocol.

## Booting Unicycle applications over the network
While booting from the disk is one of the possible options it requires generating and reflashing images to disk/USB stick every time
the Unicycle application is modified. Such workflow makes it harder to do quick iterative development.

To help to increase development speed this bootloader supports booting over the network.
The idea is derived from [Zircon](https://fuchsia.googlesource.com/zircon/+/refs/heads/master/bootloader/) project and shares many implementation details.
Once the device boots it sends a multicast request to check whether the network has a [bootserver](https://github.com/libunicycle/bootserver) running.
And if it has one it downloads the application binary file over TFTP and loads it into the device memory.

To enable network-based boot process one needs to make sure the test device UEFI configured with network enabled
then [bootserver](https://github.com/libunicycle/bootserver) need to be run at the host.

## Build project
To build UEFI bootloader binary please run
`make`

## Create bootable image
To create a bootable image please build bootloader using instructions above.
Then update bootloader config file `bootloader.cfg` to choose whether you prefer over-the-network or from-disk application boot.
Once you completed please run:

`sudo image_generate.sh`

At the end you'll get `boot.img` that is suitable for flashing to a disk or USB flash stick:

`sudo dd if=boot.img of=/dev/sdXXXX`

sdXXXX - device disk for your bootable device. You can find the name using `lsblk` tool.
73 changes: 73 additions & 0 deletions bootinfo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "bootinfo.h"

#include "uniboot.h"

#ifndef UNIBOOT_NO_BUILTIN
#include <string.h>
#include "xefi.h"
#include <stdint.h>
#endif

void *buffer;
void *ptr;
size_t available;
size_t total_size;

#ifdef UNIBOOT_NO_BUILTIN
static void memset(uint8_t *p, uint8_t c, size_t n) {
for (size_t i = 0; i < n; i++) {
*p++ = c;
}
}
#endif

void bootinfo_init(void *b, size_t size) {
buffer = b;
available = size;
total_size = size;
ptr = buffer;
memset(ptr, 0, size);

if (available < sizeof(struct uniboot_info)) {
xefi_fatal("init_boot_info: provided buffer is too small for uniboot_info", EFI_BUFFER_TOO_SMALL);
}

struct uniboot_info *hdr = ptr;
hdr->magic = UNIBOOT_MAGIC;
hdr->version = 1;
hdr->length = sizeof(struct uniboot_info);

ptr += sizeof(struct uniboot_info);
}

void bootinfo_reinit(void *b, size_t size) {
buffer = b;
struct uniboot_info *hdr = buffer;
total_size = size;
ptr = buffer + hdr->length;
available = size - hdr->length;
memset(ptr, 0, size - hdr->length);
}

void *bootinfo_finalize(void) {
return buffer;
}

void *bootinfo_alloc_size(size_t size) {
if (size > available) {
xefi_fatal("boot_info buffer is too small", EFI_BUFFER_TOO_SMALL);
}

void *p = ptr;
ptr += size;
available -= size;

struct uniboot_info *hdr = buffer;
hdr->length += size;

return p;
}

size_t bootinfo_size_available(void) { return available; }

size_t bootinfo_size_consumed(void) { return total_size - available; }
16 changes: 16 additions & 0 deletions bootinfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <stddef.h>

void bootinfo_init(void *buffer, size_t size);
void bootinfo_reinit(void *b, size_t size);

void *bootinfo_finalize(void);

void *bootinfo_alloc_size(size_t size);

#define bootinfo_alloc(type) ({ (type *)bootinfo_alloc_size(sizeof(type)); })

size_t bootinfo_size_available(void);

size_t bootinfo_size_consumed(void);
Loading

0 comments on commit 0b0eeaf

Please sign in to comment.