diff options
Diffstat (limited to 'sys/arch/arm64')
-rw-r--r-- | sys/arch/arm64/stand/efiboot/Makefile | 5 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/conf.c | 9 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/efiboot.c | 21 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/efiboot.h | 3 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/eficall.h | 10 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/efipxe.c | 293 | ||||
-rw-r--r-- | sys/arch/arm64/stand/efiboot/efipxe.h | 21 |
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 *); |