From: Michael Brown Date: Wed, 15 Jul 2026 22:28:38 +0000 (+0100) Subject: [blob] Add an abstraction of an openable data blob X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0d3d223a87d4faa665672cb194d7b591fb25b671;p=thirdparty%2Fipxe.git [blob] Add an abstraction of an openable data blob Within the iPXE data transfer interface model, openers are fully asynchronous and may not deliver any data until after the opener has returned. Provide a trivial openable data blob object (as a generalisation of the "hello world" data transfer interface example code) that will simply deliver a single fixed blob of data to its parent interface and then close itself. Signed-off-by: Michael Brown --- diff --git a/src/core/blob.c b/src/core/blob.c new file mode 100644 index 000000000..cc5ea5a93 --- /dev/null +++ b/src/core/blob.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2026 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +#include +#include +#include +#include +#include +#include + +/** @file + * + * Openable data blobs + * + * Within the iPXE data transfer interface model, openers are fully + * asynchronous and may not deliver any data until after the opener + * has returned. An openable data blob provides a way to open an + * interface that will then simply return a single fixed blob of data. + */ + +/** An openable data blob */ +struct blob { + /** Reference count */ + struct refcnt refcnt; + /** Data transfer interface */ + struct interface xfer; + /** Download process */ + struct process process; + /** Data */ + const void *data; + /** Length of data */ + size_t len; +}; + +/** + * Close data blob + * + * @v blob Data blob + * @v rc Reason for close + */ +static void blob_close ( struct blob *blob, int rc ) { + + /* Stop process */ + process_del ( &blob->process ); + + /* Shut down interface */ + intf_shutdown ( &blob->xfer, rc ); +} + +/** + * Process data blob + * + * @v blob Data blob + */ +static void blob_step ( struct blob *blob ) { + int rc; + + /* Deliver data when window opens */ + if ( xfer_window ( &blob->xfer ) ) { + rc = xfer_deliver_raw ( &blob->xfer, blob->data, blob->len ); + blob_close ( blob, rc ); + } +} + +/** Data blob interface operations */ +static struct interface_operation blob_xfer_op[] = { + INTF_OP ( xfer_window_changed, struct blob *, blob_step ), + INTF_OP ( intf_close, struct blob *, blob_close ), +}; + +/** Data blob interface descriptor */ +static struct interface_descriptor blob_xfer_desc = + INTF_DESC ( struct blob, xfer, blob_xfer_op ); + +/** Data blob process descriptor */ +static struct process_descriptor blob_process_desc = + PROC_DESC_ONCE ( struct blob, process, blob_step ); + +/** + * Open data blob + * + * @v xfer Data transfer interface + * @v data Data + * @v len Length of data + * @ret rc Return status code + */ +int blob_open ( struct interface *xfer, const void *data, size_t len ) { + struct blob *blob; + void *copy; + + /* Allocate and initialise structure */ + blob = zalloc ( sizeof ( *blob ) + len ); + if ( ! blob ) + return -ENOMEM; + ref_init ( &blob->refcnt, NULL ); + intf_init ( &blob->xfer, &blob_xfer_desc, &blob->refcnt ); + process_init ( &blob->process, &blob_process_desc, &blob->refcnt ); + copy = ( ( ( void * ) blob ) + sizeof ( *blob ) ); + blob->data = copy; + blob->len = len; + memcpy ( copy, data, len ); + + /* Attach parent interface, mortalise self, and return */ + intf_plug_plug ( &blob->xfer, xfer ); + ref_put ( &blob->refcnt ); + return 0; +} diff --git a/src/core/hw.c b/src/core/hw.c deleted file mode 100644 index 91736a652..000000000 --- a/src/core/hw.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -/** @file - * - * "Hello World" data source - * - */ - -struct hw { - struct refcnt refcnt; - struct interface xfer; - struct process process; -}; - -static const char hw_msg[] = "Hello world!\n"; - -static void hw_finished ( struct hw *hw, int rc ) { - intf_shutdown ( &hw->xfer, rc ); - process_del ( &hw->process ); -} - -static void hw_step ( struct hw *hw ) { - int rc; - - if ( xfer_window ( &hw->xfer ) ) { - rc = xfer_deliver_raw ( &hw->xfer, hw_msg, sizeof ( hw_msg ) ); - hw_finished ( hw, rc ); - } -} - -static struct interface_operation hw_xfer_operations[] = { - INTF_OP ( xfer_window_changed, struct hw *, hw_step ), - INTF_OP ( intf_close, struct hw *, hw_finished ), -}; - -static struct interface_descriptor hw_xfer_desc = - INTF_DESC ( struct hw, xfer, hw_xfer_operations ); - -static struct process_descriptor hw_process_desc = - PROC_DESC_ONCE ( struct hw, process, hw_step ); - -static int hw_open ( struct interface *xfer, struct uri *uri __unused ) { - struct hw *hw; - - /* Allocate and initialise structure */ - hw = zalloc ( sizeof ( *hw ) ); - if ( ! hw ) - return -ENOMEM; - ref_init ( &hw->refcnt, NULL ); - intf_init ( &hw->xfer, &hw_xfer_desc, &hw->refcnt ); - process_init ( &hw->process, &hw_process_desc, &hw->refcnt ); - - /* Attach parent interface, mortalise self, and return */ - intf_plug_plug ( &hw->xfer, xfer ); - ref_put ( &hw->refcnt ); - return 0; -} - -struct uri_opener hw_uri_opener __uri_opener = { - .scheme = "hw", - .open = hw_open, -}; diff --git a/src/include/ipxe/blob.h b/src/include/ipxe/blob.h new file mode 100644 index 000000000..20f7277bd --- /dev/null +++ b/src/include/ipxe/blob.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_BLOB_H +#define _IPXE_BLOB_H + +/** @file + * + * Openable data blobs + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +#include +#include + +extern int blob_open ( struct interface *xfer, const void *data, size_t len ); + +#endif /* _IPXE_BLOB_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 925530fa7..c6ebfd67f 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -41,7 +41,7 @@ FILE_SECBOOT ( PERMITTED ); #define ERRFILE_asprintf ( ERRFILE_CORE | 0x00000000 ) #define ERRFILE_downloader ( ERRFILE_CORE | 0x00010000 ) #define ERRFILE_exec ( ERRFILE_CORE | 0x00020000 ) -#define ERRFILE_hw ( ERRFILE_CORE | 0x00030000 ) +#define ERRFILE_blob ( ERRFILE_CORE | 0x00030000 ) #define ERRFILE_iobuf ( ERRFILE_CORE | 0x00040000 ) #define ERRFILE_job ( ERRFILE_CORE | 0x00050000 ) #define ERRFILE_linebuf ( ERRFILE_CORE | 0x00060000 )