mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 22bb29eabc | |||
| 8446a439b3 | |||
| 4039b54ba3 | |||
| cd3de55ea5 | |||
| d562339fca | |||
| e39cd79a00 | |||
| 057674bb1f | |||
| 19d0fab40f | |||
| fa012dd020 | |||
| d16535aa4f |
100
contrib/cloud/aws-import
Executable file
100
contrib/cloud/aws-import
Executable file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from base64 import b64encode
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from hashlib import sha256
|
||||
from itertools import count
|
||||
|
||||
import boto3
|
||||
|
||||
BLOCKSIZE = 512 * 1024
|
||||
|
||||
|
||||
def create_snapshot(region, description, image):
|
||||
"""Create an EBS snapshot"""
|
||||
client = boto3.client('ebs', region_name=region)
|
||||
snapshot = client.start_snapshot(VolumeSize=1,
|
||||
Description=description)
|
||||
snapshot_id = snapshot['SnapshotId']
|
||||
with open(image, 'rb') as fh:
|
||||
for block in count():
|
||||
data = fh.read(BLOCKSIZE)
|
||||
if not data:
|
||||
break
|
||||
data = data.ljust(BLOCKSIZE, b'\0')
|
||||
checksum = b64encode(sha256(data).digest()).decode()
|
||||
client.put_snapshot_block(SnapshotId=snapshot_id,
|
||||
BlockIndex=block,
|
||||
BlockData=data,
|
||||
DataLength=BLOCKSIZE,
|
||||
Checksum=checksum,
|
||||
ChecksumAlgorithm='SHA256')
|
||||
client.complete_snapshot(SnapshotId=snapshot_id,
|
||||
ChangedBlocksCount=block)
|
||||
return snapshot_id
|
||||
|
||||
|
||||
def import_image(region, name, architecture, image, public):
|
||||
"""Import an AMI image"""
|
||||
client = boto3.client('ec2', region_name=region)
|
||||
resource = boto3.resource('ec2', region_name=region)
|
||||
description = '%s (%s)' % (name, architecture)
|
||||
snapshot_id = create_snapshot(region=region, description=description,
|
||||
image=image)
|
||||
client.get_waiter('snapshot_completed').wait(SnapshotIds=[snapshot_id])
|
||||
image = client.register_image(Architecture=architecture,
|
||||
BlockDeviceMappings=[{
|
||||
'DeviceName': '/dev/sda1',
|
||||
'Ebs': {
|
||||
'SnapshotId': snapshot_id,
|
||||
'VolumeType': 'standard',
|
||||
},
|
||||
}],
|
||||
EnaSupport=True,
|
||||
Name=description,
|
||||
RootDeviceName='/dev/sda1',
|
||||
SriovNetSupport='simple',
|
||||
VirtualizationType='hvm')
|
||||
image_id = image['ImageId']
|
||||
client.get_waiter('image_available').wait(ImageIds=[image_id])
|
||||
if public:
|
||||
resource.Image(image_id).modify_attribute(Attribute='launchPermission',
|
||||
OperationType='add',
|
||||
UserGroups=['all'])
|
||||
return image_id
|
||||
|
||||
|
||||
# Parse command-line arguments
|
||||
parser = argparse.ArgumentParser(description="Import AWS EC2 image (AMI)")
|
||||
parser.add_argument('--architecture', '-a', default='x86_64',
|
||||
help="CPU architecture")
|
||||
parser.add_argument('--name', '-n', required=True,
|
||||
help="Image name")
|
||||
parser.add_argument('--public', '-p', action='store_true',
|
||||
help="Make image public")
|
||||
parser.add_argument('--region', '-r', action='append',
|
||||
help="AWS region(s)")
|
||||
parser.add_argument('image', help="iPXE disk image")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Use all regions if none specified
|
||||
if not args.region:
|
||||
args.region = sorted(x['RegionName'] for x in
|
||||
boto3.client('ec2').describe_regions()['Regions'])
|
||||
|
||||
# Use one thread per region to maximise parallelism
|
||||
with ThreadPoolExecutor(max_workers=len(args.region)) as executor:
|
||||
futures = {executor.submit(import_image,
|
||||
region=region,
|
||||
name=args.name,
|
||||
architecture=args.architecture,
|
||||
image=args.image,
|
||||
public=args.public): region
|
||||
for region in args.region}
|
||||
results = {futures[future]: future.result()
|
||||
for future in as_completed(futures)}
|
||||
|
||||
# Show created images
|
||||
for region in args.region:
|
||||
print("%s: %s" % (region, results[region]))
|
||||
@ -175,18 +175,18 @@ static int initrd_swap_any ( userptr_t free, size_t free_len ) {
|
||||
/* Search for adjacent image */
|
||||
for_each_image ( high ) {
|
||||
|
||||
/* If we have found the adjacent image, swap and exit */
|
||||
if ( high->data == adjacent ) {
|
||||
initrd_swap ( low, high, free, free_len );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Stop search if all remaining potential
|
||||
* adjacent images are already in the correct
|
||||
* order.
|
||||
*/
|
||||
if ( high == low )
|
||||
break;
|
||||
|
||||
/* If we have found the adjacent image, swap and exit */
|
||||
if ( high->data == adjacent ) {
|
||||
initrd_swap ( low, high, free, free_len );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
76
src/arch/x86/interface/pcbios/bios_cachedhcp.c
Normal file
76
src/arch/x86/interface/pcbios/bios_cachedhcp.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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 );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/cachedhcp.h>
|
||||
#include <realmode.h>
|
||||
#include <pxe_api.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Cached DHCP packet
|
||||
*
|
||||
*/
|
||||
|
||||
/** Cached DHCPACK physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( cached_dhcpack_phys );
|
||||
#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cached_dhcpack_phys
|
||||
|
||||
/**
|
||||
* Cached DHCPACK initialisation function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_init ( void ) {
|
||||
int rc;
|
||||
|
||||
/* Do nothing if no cached DHCPACK is present */
|
||||
if ( ! cached_dhcpack_phys ) {
|
||||
DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Record cached DHCPACK */
|
||||
if ( ( rc = cachedhcp_record ( phys_to_user ( cached_dhcpack_phys ),
|
||||
sizeof ( BOOTPLAYER_t ) ) ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n",
|
||||
strerror ( rc ) );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mark as consumed */
|
||||
cached_dhcpack_phys = 0;
|
||||
}
|
||||
|
||||
/** Cached DHCPACK initialisation function */
|
||||
struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = cachedhcp_init,
|
||||
};
|
||||
53
src/arch/x86/prefix/rawprefix.S
Normal file
53
src/arch/x86/prefix/rawprefix.S
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Raw binary prefix
|
||||
*
|
||||
* Assumes that entire image is already loaded as a contiguous block
|
||||
* on a paragraph boundary and entered in real mode.
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
.section ".prefix", "ax", @progbits
|
||||
.globl _raw_start
|
||||
_raw_start:
|
||||
|
||||
/* Adjust %cs so that %cs:0000 is the start of the image */
|
||||
movw %cs, %ax
|
||||
call 1f
|
||||
1: popw %bx
|
||||
subw $1b, %bx
|
||||
shrw $4, %bx
|
||||
addw %bx, %ax
|
||||
pushw %ax
|
||||
pushw $2f
|
||||
lret
|
||||
2:
|
||||
/* Install iPXE */
|
||||
call install
|
||||
|
||||
/* Set up real-mode stack */
|
||||
movw %bx, %ss
|
||||
movw $_estack16, %sp
|
||||
|
||||
/* Jump to .text16 segment */
|
||||
pushw %ax
|
||||
pushw $1f
|
||||
lret
|
||||
.section ".text16", "awx", @progbits
|
||||
1:
|
||||
/* Run iPXE */
|
||||
virtcall main
|
||||
|
||||
/* Uninstall iPXE */
|
||||
call uninstall
|
||||
|
||||
/* Boot next device */
|
||||
int $0x18
|
||||
@ -18,8 +18,13 @@
|
||||
* Note that the serial port output from an AWS EC2 virtual machine is
|
||||
* generally available (as the "System Log") only after the instance
|
||||
* has been stopped.
|
||||
*
|
||||
* Enable only for non-EFI builds, on the assumption that the standard
|
||||
* EFI firmware is likely to already be logging to the serial port.
|
||||
*/
|
||||
#ifndef PLATFORM_efi
|
||||
#define CONSOLE_SERIAL
|
||||
#endif
|
||||
|
||||
/* Log to partition on local disk
|
||||
*
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
/* Enable IPv6 and HTTPS */
|
||||
#define NET_PROTO_IPV6
|
||||
#define DOWNLOAD_PROTO_HTTPS
|
||||
|
||||
/* Allow retrieval of metadata (such as an iPXE boot script) from
|
||||
* Google Compute Engine metadata server.
|
||||
*/
|
||||
|
||||
@ -25,11 +25,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/dhcppkt.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <realmode.h>
|
||||
#include <pxe_api.h>
|
||||
#include <ipxe/cachedhcp.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
@ -37,50 +37,33 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
*/
|
||||
|
||||
/** Cached DHCPACK physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( cached_dhcpack_phys );
|
||||
#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cached_dhcpack_phys
|
||||
|
||||
/** Cached DHCPACK */
|
||||
static struct dhcp_packet *cached_dhcpack;
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cached_dhcpack
|
||||
|
||||
/**
|
||||
* Cached DHCPACK startup function
|
||||
* Record cached DHCPACK
|
||||
*
|
||||
* @v data DHCPACK packet buffer
|
||||
* @v max_len Maximum possible length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static void cachedhcp_init ( void ) {
|
||||
int cachedhcp_record ( userptr_t data, size_t max_len ) {
|
||||
struct dhcp_packet *dhcppkt;
|
||||
struct dhcp_packet *tmp;
|
||||
struct dhcphdr *dhcphdr;
|
||||
size_t max_len;
|
||||
size_t len;
|
||||
|
||||
/* Do nothing if no cached DHCPACK is present */
|
||||
if ( ! cached_dhcpack_phys ) {
|
||||
DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* No reliable way to determine length before parsing packet;
|
||||
* start by assuming maximum length permitted by PXE.
|
||||
*/
|
||||
max_len = sizeof ( BOOTPLAYER_t );
|
||||
|
||||
/* Allocate and populate DHCP packet */
|
||||
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
|
||||
if ( ! dhcppkt ) {
|
||||
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
|
||||
return;
|
||||
return -ENOMEM;
|
||||
}
|
||||
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
|
||||
copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
|
||||
max_len );
|
||||
copy_from_user ( dhcphdr, data, 0, max_len );
|
||||
dhcppkt_init ( dhcppkt, dhcphdr, max_len );
|
||||
|
||||
/* Shrink packet to required length. If reallocation fails,
|
||||
@ -98,10 +81,11 @@ static void cachedhcp_init ( void ) {
|
||||
dhcppkt_init ( dhcppkt, dhcphdr, len );
|
||||
|
||||
/* Store as cached DHCPACK, and mark original copy as consumed */
|
||||
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n",
|
||||
cached_dhcpack_phys, len );
|
||||
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n",
|
||||
user_to_phys ( data, 0 ), len, max_len );
|
||||
cached_dhcpack = dhcppkt;
|
||||
cached_dhcpack_phys = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,11 +104,6 @@ static void cachedhcp_startup ( void ) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Cached DHCPACK initialisation function */
|
||||
struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = cachedhcp_init,
|
||||
};
|
||||
|
||||
/** Cached DHCPACK startup function */
|
||||
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
.name = "cachedhcp",
|
||||
@ -416,6 +416,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
|
||||
if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
|
||||
return 0;
|
||||
|
||||
AR5K_EEPROM_READ(o++, val);
|
||||
switch (mode){
|
||||
case AR5K_EEPROM_MODE_11A:
|
||||
ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
|
||||
|
||||
17
src/include/ipxe/cachedhcp.h
Normal file
17
src/include/ipxe/cachedhcp.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef _IPXE_CACHEDHCP_H
|
||||
#define _IPXE_CACHEDHCP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Cached DHCP packet
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
|
||||
extern int cachedhcp_record ( userptr_t data, size_t max_len );
|
||||
|
||||
#endif /* _IPXE_CACHEDHCP_H */
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
extern void efi_set_autoboot ( void );
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
extern int efi_set_autoboot_ll_addr ( EFI_HANDLE device );
|
||||
|
||||
#endif /* _IPXE_EFI_AUTOBOOT_H */
|
||||
|
||||
16
src/include/ipxe/efi/efi_autoexec.h
Normal file
16
src/include/ipxe/efi/efi_autoexec.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _IPXE_EFI_AUTOEXEC_H
|
||||
#define _IPXE_EFI_AUTOEXEC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI autoexec script
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
extern int efi_autoexec_load ( EFI_HANDLE device );
|
||||
|
||||
#endif /* _IPXE_EFI_AUTOEXEC_H */
|
||||
16
src/include/ipxe/efi/efi_cachedhcp.h
Normal file
16
src/include/ipxe/efi/efi_cachedhcp.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _IPXE_EFI_CACHEDHCP_H
|
||||
#define _IPXE_EFI_CACHEDHCP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI cached DHCP packet
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
extern int efi_cachedhcp_record ( EFI_HANDLE device );
|
||||
|
||||
#endif /* _IPXE_EFI_CACHEDHCP_H */
|
||||
@ -76,6 +76,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_dummy_sanboot ( ERRFILE_CORE | 0x00240000 )
|
||||
#define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 )
|
||||
#define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 )
|
||||
#define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 )
|
||||
|
||||
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
|
||||
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
|
||||
@ -384,6 +385,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_ntlm ( ERRFILE_OTHER | 0x00510000 )
|
||||
#define ERRFILE_efi_veto ( ERRFILE_OTHER | 0x00520000 )
|
||||
#define ERRFILE_efi_autoboot ( ERRFILE_OTHER | 0x00530000 )
|
||||
#define ERRFILE_efi_autoexec ( ERRFILE_OTHER | 0x00540000 )
|
||||
#define ERRFILE_efi_cachedhcp ( ERRFILE_OTHER | 0x00550000 )
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@ -25,40 +25,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_autoboot.h>
|
||||
#include <ipxe/efi/Protocol/SimpleNetwork.h>
|
||||
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
|
||||
#include <ipxe/efi/Guid/FileInfo.h>
|
||||
#include <usr/autoboot.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI automatic booting
|
||||
* EFI autoboot device
|
||||
*
|
||||
*/
|
||||
|
||||
/** Autoexec script filename */
|
||||
#define AUTOEXEC_FILENAME L"autoexec.ipxe"
|
||||
|
||||
/** Autoexec script image name */
|
||||
#define AUTOEXEC_NAME "autoexec.ipxe"
|
||||
|
||||
/** Autoexec script (if any) */
|
||||
static void *efi_autoexec;
|
||||
|
||||
/** Autoexec script length */
|
||||
static size_t efi_autoexec_len;
|
||||
|
||||
/**
|
||||
* Identify autoboot device
|
||||
*
|
||||
* @v device Device handle
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
|
||||
int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
union {
|
||||
EFI_SIMPLE_NETWORK_PROTOCOL *snp;
|
||||
@ -93,172 +77,3 @@ static int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load autoexec script
|
||||
*
|
||||
* @v device Device handle
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int efi_load_autoexec ( EFI_HANDLE device ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
static wchar_t name[] = AUTOEXEC_FILENAME;
|
||||
union {
|
||||
void *interface;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
|
||||
} u;
|
||||
struct {
|
||||
EFI_FILE_INFO info;
|
||||
CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ];
|
||||
} info;
|
||||
EFI_FILE_PROTOCOL *root;
|
||||
EFI_FILE_PROTOCOL *file;
|
||||
UINTN size;
|
||||
VOID *data;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( efi_autoexec == NULL );
|
||||
assert ( efi_autoexec_len == 0 );
|
||||
|
||||
/* Open simple file system protocol */
|
||||
if ( ( efirc = bs->OpenProtocol ( device,
|
||||
&efi_simple_file_system_protocol_guid,
|
||||
&u.interface, efi_image_handle,
|
||||
device,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s has no filesystem instance: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_filesystem;
|
||||
}
|
||||
|
||||
/* Open root directory */
|
||||
if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not open volume: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_volume;
|
||||
}
|
||||
|
||||
/* Open autoexec script */
|
||||
if ( ( efirc = root->Open ( root, &file, name,
|
||||
EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s has no %ls: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_open;
|
||||
}
|
||||
|
||||
/* Get file information */
|
||||
size = sizeof ( info );
|
||||
if ( ( efirc = file->GetInfo ( file, &efi_file_info_id, &size,
|
||||
&info ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not get %ls info: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_getinfo;
|
||||
}
|
||||
size = info.info.FileSize;
|
||||
|
||||
/* Ignore zero-length files */
|
||||
if ( ! size ) {
|
||||
rc = -EINVAL;
|
||||
DBGC ( device, "EFI %s has zero-length %ls\n",
|
||||
efi_handle_name ( device ), name );
|
||||
goto err_empty;
|
||||
}
|
||||
|
||||
/* Allocate temporary copy */
|
||||
if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size,
|
||||
&data ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not allocate %ls: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Read file */
|
||||
if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not read %ls: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_read;
|
||||
}
|
||||
|
||||
/* Record autoexec script */
|
||||
efi_autoexec = data;
|
||||
efi_autoexec_len = size;
|
||||
data = NULL;
|
||||
DBGC ( device, "EFI %s found %ls\n",
|
||||
efi_handle_name ( device ), name );
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_read:
|
||||
if ( data )
|
||||
bs->FreePool ( data );
|
||||
err_alloc:
|
||||
err_empty:
|
||||
err_getinfo:
|
||||
file->Close ( file );
|
||||
err_open:
|
||||
root->Close ( root );
|
||||
err_volume:
|
||||
bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid,
|
||||
efi_image_handle, device );
|
||||
err_filesystem:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure automatic booting
|
||||
*
|
||||
*/
|
||||
void efi_set_autoboot ( void ) {
|
||||
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
|
||||
|
||||
/* Identify autoboot device, if any */
|
||||
efi_set_autoboot_ll_addr ( device );
|
||||
|
||||
/* Load autoexec script, if any */
|
||||
efi_load_autoexec ( device );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register automatic boot image
|
||||
*
|
||||
*/
|
||||
static void efi_autoboot_startup ( void ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
|
||||
const char *name = AUTOEXEC_NAME;
|
||||
struct image *image;
|
||||
|
||||
/* Do nothing if we have no autoexec script */
|
||||
if ( ! efi_autoexec )
|
||||
return;
|
||||
|
||||
/* Create autoexec image */
|
||||
image = image_memory ( name, virt_to_user ( efi_autoexec ),
|
||||
efi_autoexec_len );
|
||||
if ( ! image ) {
|
||||
DBGC ( device, "EFI %s could not create %s\n",
|
||||
efi_handle_name ( device ), name );
|
||||
return;
|
||||
}
|
||||
DBGC ( device, "EFI %s registered %s\n",
|
||||
efi_handle_name ( device ), name );
|
||||
|
||||
/* Free temporary copy */
|
||||
bs->FreePool ( efi_autoexec );
|
||||
efi_autoexec = NULL;
|
||||
}
|
||||
|
||||
/** Automatic boot startup function */
|
||||
struct startup_fn efi_autoboot_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
|
||||
.name = "efi_autoboot",
|
||||
.startup = efi_autoboot_startup,
|
||||
};
|
||||
|
||||
206
src/interface/efi/efi_autoexec.c
Normal file
206
src/interface/efi/efi_autoexec.c
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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 );
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_autoexec.h>
|
||||
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
|
||||
#include <ipxe/efi/Guid/FileInfo.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI autoexec script
|
||||
*
|
||||
*/
|
||||
|
||||
/** Autoexec script filename */
|
||||
#define AUTOEXEC_FILENAME L"autoexec.ipxe"
|
||||
|
||||
/** Autoexec script image name */
|
||||
#define AUTOEXEC_NAME "autoexec.ipxe"
|
||||
|
||||
/** Autoexec script (if any) */
|
||||
static void *efi_autoexec;
|
||||
|
||||
/** Autoexec script length */
|
||||
static size_t efi_autoexec_len;
|
||||
|
||||
/**
|
||||
* Load autoexec script
|
||||
*
|
||||
* @v device Device handle
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int efi_autoexec_load ( EFI_HANDLE device ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
static wchar_t name[] = AUTOEXEC_FILENAME;
|
||||
union {
|
||||
void *interface;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
|
||||
} u;
|
||||
struct {
|
||||
EFI_FILE_INFO info;
|
||||
CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ];
|
||||
} info;
|
||||
EFI_FILE_PROTOCOL *root;
|
||||
EFI_FILE_PROTOCOL *file;
|
||||
UINTN size;
|
||||
VOID *data;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( efi_autoexec == NULL );
|
||||
assert ( efi_autoexec_len == 0 );
|
||||
|
||||
/* Open simple file system protocol */
|
||||
if ( ( efirc = bs->OpenProtocol ( device,
|
||||
&efi_simple_file_system_protocol_guid,
|
||||
&u.interface, efi_image_handle,
|
||||
device,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s has no filesystem instance: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_filesystem;
|
||||
}
|
||||
|
||||
/* Open root directory */
|
||||
if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not open volume: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_volume;
|
||||
}
|
||||
|
||||
/* Open autoexec script */
|
||||
if ( ( efirc = root->Open ( root, &file, name,
|
||||
EFI_FILE_MODE_READ, 0 ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s has no %ls: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_open;
|
||||
}
|
||||
|
||||
/* Get file information */
|
||||
size = sizeof ( info );
|
||||
if ( ( efirc = file->GetInfo ( file, &efi_file_info_id, &size,
|
||||
&info ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not get %ls info: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_getinfo;
|
||||
}
|
||||
size = info.info.FileSize;
|
||||
|
||||
/* Ignore zero-length files */
|
||||
if ( ! size ) {
|
||||
rc = -EINVAL;
|
||||
DBGC ( device, "EFI %s has zero-length %ls\n",
|
||||
efi_handle_name ( device ), name );
|
||||
goto err_empty;
|
||||
}
|
||||
|
||||
/* Allocate temporary copy */
|
||||
if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size,
|
||||
&data ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not allocate %ls: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Read file */
|
||||
if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s could not read %ls: %s\n",
|
||||
efi_handle_name ( device ), name, strerror ( rc ) );
|
||||
goto err_read;
|
||||
}
|
||||
|
||||
/* Record autoexec script */
|
||||
efi_autoexec = data;
|
||||
efi_autoexec_len = size;
|
||||
data = NULL;
|
||||
DBGC ( device, "EFI %s found %ls\n",
|
||||
efi_handle_name ( device ), name );
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_read:
|
||||
if ( data )
|
||||
bs->FreePool ( data );
|
||||
err_alloc:
|
||||
err_empty:
|
||||
err_getinfo:
|
||||
file->Close ( file );
|
||||
err_open:
|
||||
root->Close ( root );
|
||||
err_volume:
|
||||
bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid,
|
||||
efi_image_handle, device );
|
||||
err_filesystem:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register autoexec script
|
||||
*
|
||||
*/
|
||||
static void efi_autoexec_startup ( void ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
|
||||
const char *name = AUTOEXEC_NAME;
|
||||
struct image *image;
|
||||
|
||||
/* Do nothing if we have no autoexec script */
|
||||
if ( ! efi_autoexec )
|
||||
return;
|
||||
|
||||
/* Create autoexec image */
|
||||
image = image_memory ( name, virt_to_user ( efi_autoexec ),
|
||||
efi_autoexec_len );
|
||||
if ( ! image ) {
|
||||
DBGC ( device, "EFI %s could not create %s\n",
|
||||
efi_handle_name ( device ), name );
|
||||
return;
|
||||
}
|
||||
DBGC ( device, "EFI %s registered %s\n",
|
||||
efi_handle_name ( device ), name );
|
||||
|
||||
/* Free temporary copy */
|
||||
bs->FreePool ( efi_autoexec );
|
||||
efi_autoexec = NULL;
|
||||
}
|
||||
|
||||
/** Autoexec script startup function */
|
||||
struct startup_fn efi_autoexec_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
|
||||
.name = "efi_autoexec",
|
||||
.startup = efi_autoexec_startup,
|
||||
};
|
||||
94
src/interface/efi/efi_cachedhcp.c
Normal file
94
src/interface/efi/efi_cachedhcp.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* 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 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 );
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/cachedhcp.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_cachedhcp.h>
|
||||
#include <ipxe/efi/Protocol/PxeBaseCode.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI cached DHCP packet
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Record cached DHCP packet
|
||||
*
|
||||
* @v device Device handle
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int efi_cachedhcp_record ( EFI_HANDLE device ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
union {
|
||||
EFI_PXE_BASE_CODE_PROTOCOL *pxe;
|
||||
void *interface;
|
||||
} pxe;
|
||||
EFI_PXE_BASE_CODE_MODE *mode;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Look for a PXE base code instance on the image's device handle */
|
||||
if ( ( efirc = bs->OpenProtocol ( device,
|
||||
&efi_pxe_base_code_protocol_guid,
|
||||
&pxe.interface, efi_image_handle,
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFI %s has no PXE base code instance: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_open;
|
||||
}
|
||||
|
||||
/* Do not attempt to cache IPv6 packets */
|
||||
mode = pxe.pxe->Mode;
|
||||
if ( mode->UsingIpv6 ) {
|
||||
rc = -ENOTSUP;
|
||||
DBGC ( device, "EFI %s has IPv6 PXE base code\n",
|
||||
efi_handle_name ( device ) );
|
||||
goto err_ipv6;
|
||||
}
|
||||
|
||||
/* Record DHCPACK, if present */
|
||||
if ( mode->DhcpAckReceived &&
|
||||
( ( rc = cachedhcp_record ( virt_to_user ( &mode->DhcpAck ),
|
||||
sizeof ( mode->DhcpAck ) ) ) != 0 ) ) {
|
||||
DBGC ( device, "EFI %s could not record DHCPACK: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_record;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_record:
|
||||
err_ipv6:
|
||||
bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid,
|
||||
efi_image_handle, NULL );
|
||||
err_open:
|
||||
return rc;
|
||||
}
|
||||
@ -22,10 +22,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_driver.h>
|
||||
#include <ipxe/efi/efi_snp.h>
|
||||
#include <ipxe/efi/efi_autoboot.h>
|
||||
#include <ipxe/efi/efi_autoexec.h>
|
||||
#include <ipxe/efi/efi_cachedhcp.h>
|
||||
#include <ipxe/efi/efi_watchdog.h>
|
||||
#include <ipxe/efi/efi_veto.h>
|
||||
|
||||
@ -48,9 +51,6 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
|
||||
if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 )
|
||||
goto err_init;
|
||||
|
||||
/* Record autoboot device (if any) */
|
||||
efi_set_autoboot();
|
||||
|
||||
/* Claim SNP devices for use by iPXE */
|
||||
efi_snp_claim();
|
||||
|
||||
@ -72,6 +72,28 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
|
||||
return efirc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise EFI application
|
||||
*
|
||||
*/
|
||||
static void efi_init_application ( void ) {
|
||||
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
|
||||
|
||||
/* Identify autoboot device, if any */
|
||||
efi_set_autoboot_ll_addr ( device );
|
||||
|
||||
/* Store cached DHCP packet, if any */
|
||||
efi_cachedhcp_record ( device );
|
||||
|
||||
/* Load autoexec script, if any */
|
||||
efi_autoexec_load ( device );
|
||||
}
|
||||
|
||||
/** EFI application initialisation function */
|
||||
struct init_fn efi_init_application_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = efi_init_application,
|
||||
};
|
||||
|
||||
/**
|
||||
* Probe EFI root bus
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user