~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/interface/efi/efi_download.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License as
 
6
 * published by the Free Software Foundation; either version 2 of the
 
7
 * License, or any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but
 
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
17
 */
 
18
 
 
19
FILE_LICENCE ( GPL2_OR_LATER );
 
20
 
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <errno.h>
 
24
#include <ipxe/open.h>
 
25
#include <ipxe/process.h>
 
26
#include <ipxe/iobuf.h>
 
27
#include <ipxe/xfer.h>
 
28
#include <ipxe/efi/efi.h>
 
29
#include <ipxe/efi/efi_snp.h>
 
30
#include <ipxe/efi/efi_download.h>
 
31
 
 
32
/** iPXE download protocol GUID */
 
33
static EFI_GUID ipxe_download_protocol_guid
 
34
        = IPXE_DOWNLOAD_PROTOCOL_GUID;
 
35
 
 
36
/** A single in-progress file */
 
37
struct efi_download_file {
 
38
        /** Data transfer interface that provides downloaded data */
 
39
        struct interface xfer;
 
40
 
 
41
        /** Current file position */
 
42
        size_t pos;
 
43
 
 
44
        /** Data callback */
 
45
        IPXE_DOWNLOAD_DATA_CALLBACK data_callback;
 
46
 
 
47
        /** Finish callback */
 
48
        IPXE_DOWNLOAD_FINISH_CALLBACK finish_callback;
 
49
 
 
50
        /** Callback context */
 
51
        void *context;
 
52
};
 
53
 
 
54
/* xfer interface */
 
55
 
 
56
/**
 
57
 * Transfer finished or was aborted
 
58
 *
 
59
 * @v file              Data transfer file
 
60
 * @v rc                Reason for close
 
61
 */
 
62
static void efi_download_close ( struct efi_download_file *file, int rc ) {
 
63
 
 
64
        file->finish_callback ( file->context, EFIRC ( rc ) );
 
65
 
 
66
        intf_shutdown ( &file->xfer, rc );
 
67
 
 
68
        efi_snp_release();
 
69
}
 
70
 
 
71
/**
 
72
 * Process received data
 
73
 *
 
74
 * @v file              Data transfer file
 
75
 * @v iobuf             I/O buffer
 
76
 * @v meta              Data transfer metadata
 
77
 * @ret rc              Return status code
 
78
 */
 
79
static int efi_download_deliver_iob ( struct efi_download_file *file,
 
80
                                      struct io_buffer *iobuf,
 
81
                                      struct xfer_metadata *meta ) {
 
82
        EFI_STATUS efirc;
 
83
        size_t len = iob_len ( iobuf );
 
84
        int rc;
 
85
 
 
86
        /* Calculate new buffer position */
 
87
        if ( meta->flags & XFER_FL_ABS_OFFSET )
 
88
                file->pos = 0;
 
89
        file->pos += meta->offset;
 
90
 
 
91
        /* Call out to the data handler */
 
92
        if ( ( efirc = file->data_callback ( file->context, iobuf->data,
 
93
                                             len, file->pos ) ) != 0 ) {
 
94
                rc = -EEFI ( efirc );
 
95
                goto err_callback;
 
96
        }
 
97
 
 
98
        /* Update current buffer position */
 
99
        file->pos += len;
 
100
 
 
101
        /* Success */
 
102
        rc = 0;
 
103
 
 
104
 err_callback:
 
105
        free_iob ( iobuf );
 
106
        return rc;
 
107
}
 
108
 
 
109
/** Data transfer interface operations */
 
110
static struct interface_operation efi_xfer_operations[] = {
 
111
        INTF_OP ( xfer_deliver, struct efi_download_file *, efi_download_deliver_iob ),
 
112
        INTF_OP ( intf_close, struct efi_download_file *, efi_download_close ),
 
113
};
 
114
 
 
115
/** EFI download data transfer interface descriptor */
 
116
static struct interface_descriptor efi_download_file_xfer_desc =
 
117
        INTF_DESC ( struct efi_download_file, xfer, efi_xfer_operations );
 
118
 
 
119
/**
 
120
 * Start downloading a file, and register callback functions to handle the
 
121
 * download.
 
122
 *
 
123
 * @v This              iPXE Download Protocol instance
 
124
 * @v Url               URL to download from
 
125
 * @v DataCallback      Callback that will be invoked when data arrives
 
126
 * @v FinishCallback    Callback that will be invoked when the download ends
 
127
 * @v Context           Context passed to the Data and Finish callbacks
 
128
 * @v File              Token that can be used to abort the download
 
129
 * @ret Status          EFI status code
 
130
 */
 
131
static EFI_STATUS EFIAPI
 
132
efi_download_start ( IPXE_DOWNLOAD_PROTOCOL *This __unused,
 
133
                     CHAR8 *Url,
 
134
                     IPXE_DOWNLOAD_DATA_CALLBACK DataCallback,
 
135
                     IPXE_DOWNLOAD_FINISH_CALLBACK FinishCallback,
 
136
                     VOID *Context,
 
137
                     IPXE_DOWNLOAD_FILE *File ) {
 
138
        struct efi_download_file *file;
 
139
        int rc;
 
140
 
 
141
        file = malloc ( sizeof ( struct efi_download_file ) );
 
142
        if ( file == NULL ) {
 
143
                return EFI_OUT_OF_RESOURCES;
 
144
        }
 
145
 
 
146
        intf_init ( &file->xfer, &efi_download_file_xfer_desc, NULL );
 
147
        rc = xfer_open ( &file->xfer, LOCATION_URI_STRING, Url );
 
148
        if ( rc ) {
 
149
                free ( file );
 
150
                return EFIRC ( rc );
 
151
        }
 
152
 
 
153
        efi_snp_claim();
 
154
        file->pos = 0;
 
155
        file->data_callback = DataCallback;
 
156
        file->finish_callback = FinishCallback;
 
157
        file->context = Context;
 
158
        *File = file;
 
159
        return EFI_SUCCESS;
 
160
}
 
161
 
 
162
/**
 
163
 * Forcibly abort downloading a file that is currently in progress.
 
164
 *
 
165
 * It is not safe to call this function after the Finish callback has executed.
 
166
 *
 
167
 * @v This              iPXE Download Protocol instance
 
168
 * @v File              Token obtained from Start
 
169
 * @v Status            Reason for aborting the download
 
170
 * @ret Status          EFI status code
 
171
 */
 
172
static EFI_STATUS EFIAPI
 
173
efi_download_abort ( IPXE_DOWNLOAD_PROTOCOL *This __unused,
 
174
                     IPXE_DOWNLOAD_FILE File,
 
175
                     EFI_STATUS Status ) {
 
176
        struct efi_download_file *file = File;
 
177
 
 
178
        efi_download_close ( file, -EEFI ( Status ) );
 
179
        return EFI_SUCCESS;
 
180
}
 
181
 
 
182
/**
 
183
 * Poll for more data from iPXE. This function will invoke the registered
 
184
 * callbacks if data is available or if downloads complete.
 
185
 *
 
186
 * @v This              iPXE Download Protocol instance
 
187
 * @ret Status          EFI status code
 
188
 */
 
189
static EFI_STATUS EFIAPI
 
190
efi_download_poll ( IPXE_DOWNLOAD_PROTOCOL *This __unused ) {
 
191
        step();
 
192
        return EFI_SUCCESS;
 
193
}
 
194
 
 
195
/** Publicly exposed iPXE download protocol */
 
196
static IPXE_DOWNLOAD_PROTOCOL ipxe_download_protocol_interface = {
 
197
        .Start = efi_download_start,
 
198
        .Abort = efi_download_abort,
 
199
        .Poll = efi_download_poll
 
200
};
 
201
 
 
202
/**
 
203
 * Install iPXE download protocol
 
204
 *
 
205
 * @v handle            EFI handle
 
206
 * @ret rc              Return status code
 
207
 */
 
208
int efi_download_install ( EFI_HANDLE handle ) {
 
209
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 
210
        EFI_STATUS efirc;
 
211
        int rc;
 
212
 
 
213
        efirc = bs->InstallMultipleProtocolInterfaces (
 
214
                        &handle,
 
215
                        &ipxe_download_protocol_guid,
 
216
                        &ipxe_download_protocol_interface,
 
217
                        NULL );
 
218
        if ( efirc ) {
 
219
                rc = -EEFI ( efirc );
 
220
                DBG ( "Could not install download protocol: %s\n",
 
221
                      strerror ( rc ) );
 
222
                return rc;
 
223
        }
 
224
 
 
225
        return 0;
 
226
}
 
227
 
 
228
/**
 
229
 * Uninstall iPXE download protocol
 
230
 *
 
231
 * @v handle            EFI handle
 
232
 */
 
233
void efi_download_uninstall ( EFI_HANDLE handle ) {
 
234
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 
235
 
 
236
        bs->UninstallMultipleProtocolInterfaces (
 
237
                        handle,
 
238
                        &ipxe_download_protocol_guid,
 
239
                        &ipxe_download_protocol_interface, NULL );
 
240
}