summaryrefslogtreecommitdiff
path: root/sys/arch/arm64
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/arm64')
-rw-r--r--sys/arch/arm64/stand/efiboot/Makefile5
-rw-r--r--sys/arch/arm64/stand/efiboot/conf.c9
-rw-r--r--sys/arch/arm64/stand/efiboot/efiboot.c21
-rw-r--r--sys/arch/arm64/stand/efiboot/efiboot.h3
-rw-r--r--sys/arch/arm64/stand/efiboot/eficall.h10
-rw-r--r--sys/arch/arm64/stand/efiboot/efipxe.c293
-rw-r--r--sys/arch/arm64/stand/efiboot/efipxe.h21
7 files changed, 345 insertions, 17 deletions
diff --git a/sys/arch/arm64/stand/efiboot/Makefile b/sys/arch/arm64/stand/efiboot/Makefile
index 324528d3c8e..256d42c22ad 100644
--- a/sys/arch/arm64/stand/efiboot/Makefile
+++ b/sys/arch/arm64/stand/efiboot/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.2 2017/07/17 13:46:53 kettenis Exp $
+# $OpenBSD: Makefile,v 1.3 2018/01/21 21:35:34 patrick Exp $
NOMAN= #
@@ -8,7 +8,8 @@ PROG= BOOTAA64.EFI
OBJFMT= binary
INSTALL_STRIP=
BINDIR= /usr/mdec
-SRCS= start.S self_reloc.c efiboot.c conf.c exec.c efidev.c fdt.c
+SRCS= start.S self_reloc.c efiboot.c conf.c exec.c efidev.c efipxe.c
+SRCS+= fdt.c
S= ${.CURDIR}/../../../..
EFIDIR= ${S}/stand/efi
diff --git a/sys/arch/arm64/stand/efiboot/conf.c b/sys/arch/arm64/stand/efiboot/conf.c
index 0fa040972e6..e504d624820 100644
--- a/sys/arch/arm64/stand/efiboot/conf.c
+++ b/sys/arch/arm64/stand/efiboot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.9 2017/09/08 05:36:51 deraadt Exp $ */
+/* $OpenBSD: conf.c,v 1.10 2018/01/21 21:35:34 patrick Exp $ */
/*
* Copyright (c) 1996 Michael Shalayeff
@@ -28,22 +28,27 @@
#include <sys/param.h>
#include <lib/libsa/stand.h>
+#include <lib/libsa/tftp.h>
#include <lib/libsa/ufs.h>
#include <dev/cons.h>
#include "efiboot.h"
#include "efidev.h"
+#include "efipxe.h"
-const char version[] = "0.8";
+const char version[] = "0.9";
int debug = 0;
struct fs_ops file_system[] = {
+ { tftp_open, tftp_close, tftp_read, tftp_write, tftp_seek,
+ tftp_stat, tftp_readdir },
{ ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek,
ufs_stat, ufs_readdir },
};
int nfsys = nitems(file_system);
struct devsw devsw[] = {
+ { "tftp", tftpstrategy, tftpopen, tftpclose, tftpioctl },
{ "sd", efistrategy, efiopen, eficlose, efiioctl },
};
int ndevs = nitems(devsw);
diff --git a/sys/arch/arm64/stand/efiboot/efiboot.c b/sys/arch/arm64/stand/efiboot/efiboot.c
index a416ba02a76..c8654196bcf 100644
--- a/sys/arch/arm64/stand/efiboot/efiboot.c
+++ b/sys/arch/arm64/stand/efiboot/efiboot.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: efiboot.c,v 1.13 2017/08/23 18:03:54 kettenis Exp $ */
+/* $OpenBSD: efiboot.c,v 1.14 2018/01/21 21:35:34 patrick Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -31,6 +31,7 @@
#include <stand/boot/cmd.h>
#include "disk.h"
+#include "efiboot.h"
#include "eficall.h"
#include "fdt.h"
#include "libsa.h"
@@ -53,8 +54,8 @@ static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
-static int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
-static int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
+int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
+int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
static void efi_heap_init(void);
static void efi_memprobe_internal(void);
static void efi_timer_init(void);
@@ -188,7 +189,7 @@ efi_diskprobe(void)
0, &sz, handles);
}
if (handles == NULL || EFI_ERROR(status))
- panic("BS->LocateHandle() returns %d", status);
+ return;
if (efi_bootdp != NULL)
depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
@@ -231,7 +232,7 @@ efi_diskprobe(void)
* Determine the number of nodes up to, but not including, the first
* node of the specified type.
*/
-static int
+int
efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
{
int i;
@@ -244,7 +245,7 @@ efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype)
return (-1);
}
-static int
+int
efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn)
{
int i, cmp;
@@ -457,6 +458,7 @@ machdep(void)
efi_timer_init();
efi_diskprobe();
+ efi_pxeprobe();
}
void
@@ -540,7 +542,10 @@ getsecs(void)
void
devboot(dev_t dev, char *p)
{
- strlcpy(p, "sd0a", 5);
+ if (disk)
+ strlcpy(p, "sd0a", 5);
+ else
+ strlcpy(p, "tftp0a", 7);
}
int
@@ -641,7 +646,7 @@ devopen(struct open_file *f, const char *fname, char **file)
if (error)
return (error);
- dp = &devsw[0];
+ dp = &devsw[dev];
f->f_dev = dp;
return (*dp->dv_open)(f, unit, part);
diff --git a/sys/arch/arm64/stand/efiboot/efiboot.h b/sys/arch/arm64/stand/efiboot/efiboot.h
index 87d92558d10..8f69bb715a1 100644
--- a/sys/arch/arm64/stand/efiboot/efiboot.h
+++ b/sys/arch/arm64/stand/efiboot/efiboot.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: efiboot.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $OpenBSD: efiboot.h,v 1.2 2018/01/21 21:35:34 patrick Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -18,6 +18,7 @@
void efi_cleanup(void);
void efi_diskprobe(void);
+void efi_pxeprobe(void);
void *efi_makebootargs(char *);
void efi_cons_probe(struct consdev *);
void efi_cons_init(struct consdev *);
diff --git a/sys/arch/arm64/stand/efiboot/eficall.h b/sys/arch/arm64/stand/efiboot/eficall.h
index 6f4c2168acc..dbf2e718a88 100644
--- a/sys/arch/arm64/stand/efiboot/eficall.h
+++ b/sys/arch/arm64/stand/efiboot/eficall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: eficall.h,v 1.2 2016/12/30 09:43:18 yasuoka Exp $ */
+/* $OpenBSD: eficall.h,v 1.3 2018/01/21 21:35:34 patrick Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -44,10 +44,12 @@ extern uint64_t efi_call(int, void *, ...);
efi_call(8, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8))
#define _call_9(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
efi_call(9, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8), (_9))
+#define _call_10(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
+ efi_call(10, (_func), (_1), (_2), (_3), (_4), (_5), (_6), (_7), (_8), (_9), (_10))
-#define _efi_call_fn(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9, _fn, ...) _fn
+#define _efi_call_fn(_func, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _fn, ...) _fn
#define EFI_CALL(...) \
- _efi_call_fn(__VA_ARGS__, _call_9, _call_8, _call_7, _call_6, _call_5, \
- _call_4, _call_3, _call_2, _call_1, _call_0)(__VA_ARGS__)
+ _efi_call_fn(__VA_ARGS__, _call_10, _call_9, _call_8, _call_7, _call_6, \
+ _call_5, _call_4, _call_3, _call_2, _call_1, _call_0)(__VA_ARGS__)
#endif
diff --git a/sys/arch/arm64/stand/efiboot/efipxe.c b/sys/arch/arm64/stand/efiboot/efipxe.c
new file mode 100644
index 00000000000..d0684ea7c33
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/efipxe.c
@@ -0,0 +1,293 @@
+/* $OpenBSD: efipxe.c,v 1.1 2018/01/21 21:35:34 patrick Exp $ */
+/*
+ * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/disklabel.h>
+
+#include <libsa.h>
+#include <lib/libsa/tftp.h>
+
+#include <efi.h>
+#include <efiapi.h>
+#include "eficall.h"
+#include "efiboot.h"
+#include "disk.h"
+
+extern EFI_BOOT_SERVICES *BS;
+extern EFI_DEVICE_PATH *efi_bootdp;
+
+static UINT8 boothw[16];
+static EFI_IP_ADDRESS bootip, servip;
+static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL;
+static EFI_GUID pxe_guid = EFI_PXE_BASE_CODE_PROTOCOL;
+static EFI_PXE_BASE_CODE *PXE = NULL;
+
+extern int efi_device_path_depth(EFI_DEVICE_PATH *dp, int);
+extern int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
+
+/*
+ * TFTP initial probe. This function discovers PXE handles and tries
+ * to figure out if there has already been a successfull PXE handshake.
+ * If so, set the PXE variable.
+ */
+void
+efi_pxeprobe(void)
+{
+ EFI_PXE_BASE_CODE *pxe;
+ EFI_DEVICE_PATH *dp0;
+ EFI_HANDLE *handles;
+ EFI_STATUS status;
+ UINTN nhandles;
+ int i, depth;
+
+ if (efi_bootdp == NULL)
+ return;
+
+ status = EFI_CALL(BS->LocateHandleBuffer, ByProtocol, &pxe_guid, NULL,
+ &nhandles, &handles);
+ if (status != EFI_SUCCESS)
+ return;
+
+ for (i = 0; i < nhandles; i++) {
+ EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp = NULL;
+
+ status = EFI_CALL(BS->HandleProtocol, handles[i],
+ &devp_guid, (void **)&dp0);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
+ if (efi_device_path_ncmp(efi_bootdp, dp0, depth))
+ continue;
+
+ status = EFI_CALL(BS->HandleProtocol, handles[i], &pxe_guid,
+ (void **)&pxe);
+ if (status != EFI_SUCCESS)
+ continue;
+
+ if (pxe->Mode == NULL)
+ continue;
+
+ if (pxe->Mode->DhcpAckReceived) {
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)
+ &pxe->Mode->DhcpAck;
+ }
+ if (pxe->Mode->PxeReplyReceived) {
+ dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)
+ &pxe->Mode->PxeReply;
+ }
+
+ if (dhcp) {
+ memcpy(&bootip, dhcp->BootpYiAddr, sizeof(bootip));
+ memcpy(&servip, dhcp->BootpSiAddr, sizeof(servip));
+ memcpy(boothw, dhcp->BootpHwAddr, sizeof(boothw));
+ PXE = pxe;
+ break;
+ }
+ }
+}
+
+/*
+ * TFTP filesystem layer implementation.
+ */
+struct tftp_handle {
+ unsigned char *inbuf; /* input buffer */
+ size_t inbufsize;
+ off_t inbufoff;
+};
+
+struct fs_ops tftp_fs = {
+ tftp_open, tftp_close, tftp_read, tftp_write, tftp_seek,
+ tftp_stat, tftp_readdir
+};
+
+int
+tftp_open(char *path, struct open_file *f)
+{
+ struct tftp_handle *tftpfile;
+ EFI_PHYSICAL_ADDRESS addr;
+ EFI_STATUS status;
+ UINT64 size;
+
+ if (PXE == NULL)
+ return ENXIO;
+
+ tftpfile = alloc(sizeof(*tftpfile));
+ if (tftpfile == NULL)
+ return ENOMEM;
+ memset(tftpfile, 0, sizeof(*tftpfile));
+
+ status = EFI_CALL(PXE->Mtftp, PXE, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ NULL, FALSE, &size, NULL, &servip, path, NULL, FALSE);
+ if (status != EFI_SUCCESS) {
+ free(tftpfile, sizeof(*tftpfile));
+ return ENOENT;
+ }
+ tftpfile->inbufsize = size;
+
+ status = EFI_CALL(BS->AllocatePages, AllocateAnyPages, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(tftpfile->inbufsize), &addr);
+ if (status != EFI_SUCCESS) {
+ free(tftpfile, sizeof(*tftpfile));
+ return ENOMEM;
+ }
+ tftpfile->inbuf = (unsigned char *)((paddr_t)addr);
+
+ status = EFI_CALL(PXE->Mtftp, PXE, EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ tftpfile->inbuf, FALSE, &size, NULL, &servip, path, NULL, FALSE);
+ if (status != EFI_SUCCESS) {
+ free(tftpfile, sizeof(*tftpfile));
+ return ENXIO;
+ }
+
+ f->f_fsdata = tftpfile;
+ return 0;
+}
+
+int
+tftp_close(struct open_file *f)
+{
+ struct tftp_handle *tftpfile = f->f_fsdata;
+
+ EFI_CALL(BS->FreePages, (paddr_t)tftpfile->inbuf,
+ EFI_SIZE_TO_PAGES(tftpfile->inbufsize));
+ free(tftpfile, sizeof(*tftpfile));
+ return 0;
+}
+
+int
+tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid)
+{
+ struct tftp_handle *tftpfile = f->f_fsdata;
+ size_t toread;
+
+ if (size > tftpfile->inbufsize - tftpfile->inbufoff)
+ toread = tftpfile->inbufsize - tftpfile->inbufoff;
+ else
+ toread = size;
+
+ if (toread == 0) {
+ if (resid != NULL)
+ *resid = 0;
+ return (0);
+ }
+
+ memcpy(addr, tftpfile->inbuf + tftpfile->inbufoff, toread);
+ tftpfile->inbufoff += toread;
+
+ if (resid != NULL)
+ *resid = size - toread;
+ return 0;
+}
+
+int
+tftp_write(struct open_file *f, void *start, size_t size, size_t *resid)
+{
+ return EROFS;
+}
+
+off_t
+tftp_seek(struct open_file *f, off_t offset, int where)
+{
+ struct tftp_handle *tftpfile = f->f_fsdata;
+
+ switch(where) {
+ case SEEK_CUR:
+ if (tftpfile->inbufoff + offset < 0) {
+ errno = EOFFSET;
+ break;
+ }
+ tftpfile->inbufoff += offset;
+ return (tftpfile->inbufoff);
+ case SEEK_SET:
+ if (offset < 0 || offset > tftpfile->inbufsize) {
+ errno = EOFFSET;
+ break;
+ }
+ tftpfile->inbufoff = offset;
+ return (tftpfile->inbufoff);
+ case SEEK_END:
+ tftpfile->inbufoff = tftpfile->inbufsize;
+ return (tftpfile->inbufoff);
+ default:
+ errno = EINVAL;
+ }
+ return((off_t)-1);
+}
+
+int
+tftp_stat(struct open_file *f, struct stat *sb)
+{
+ struct tftp_handle *tftpfile = f->f_fsdata;
+
+ sb->st_mode = 0444;
+ sb->st_nlink = 1;
+ sb->st_uid = 0;
+ sb->st_gid = 0;
+ sb->st_size = tftpfile->inbufsize;
+
+ return 0;
+}
+
+int
+tftp_readdir(struct open_file *f, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/*
+ * Dummy TFTP network device.
+ */
+int
+tftpopen(struct open_file *f, ...)
+{
+ u_int unit, part;
+ va_list ap;
+
+ va_start(ap, f);
+ unit = va_arg(ap, u_int);
+ part = va_arg(ap, u_int);
+ va_end(ap);
+
+ /* No PXE set -> no PXE available */
+ if (PXE == NULL)
+ return 1;
+
+ if (unit != 0)
+ return 1;
+
+ return 0;
+}
+
+int
+tftpclose(struct open_file *f)
+{
+ return 0;
+}
+
+int
+tftpioctl(struct open_file *f, u_long cmd, void *data)
+{
+ return EOPNOTSUPP;
+}
+
+int
+tftpstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf,
+ size_t *rsize)
+{
+ return EOPNOTSUPP;
+}
diff --git a/sys/arch/arm64/stand/efiboot/efipxe.h b/sys/arch/arm64/stand/efiboot/efipxe.h
new file mode 100644
index 00000000000..3ff18e0d601
--- /dev/null
+++ b/sys/arch/arm64/stand/efiboot/efipxe.h
@@ -0,0 +1,21 @@
+/* $OpenBSD: efipxe.h,v 1.1 2018/01/21 21:35:34 patrick Exp $ */
+/*
+ * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+int tftpopen(struct open_file *, ...);
+int tftpclose(struct open_file *);
+int tftpioctl(struct open_file *, u_long, void *);
+int tftpstrategy(void *, int, daddr32_t, size_t, void *, size_t *);