Pull request for UEFI sub-system for v2019.10-rc4 (3)

This includes the patches from
 Pull request for UEFI sub-system for v2019.10-rc4 (2)
 
 Fix UEFI specification compliance issues in the simple network protocol:
 
 * Correctly set and reset the interrupt status.
 * Support filling the header in the Transmit() service.
 * Correct the checking and setting of the network state.
 * Implement the MCastIPtoMAC() service.
 * Adjust the simple network protocol unit test.
 
 Fix UEFI specification compliance issues in the protocol.
 
 Fix UEFI specification compliance issues in the simple text output protocol:
 * Avoid out of bounds cursor position.
 * Do not set illegal screen mode.
 
 Fix UEFI specification compliance issues in the  block IO protocol:
 * Check parameters.
 * Return correct status code if buffer is unaligned.
 
 Refactor initialization of EFI memory in preparation of support for
 > 3GB memory on x86.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAl1yCFgACgkQxIHbvCwF
 GsTRJw/+OfIhZKGdHbRNRLW2Q1TevQmp2cdU3B1RZkncxxSrALgEl09I3qicMJeV
 9+6TU7/lfv6tJCIbURilz4pq1J6JGSsEv42tzRDHmqw4MJgvFdNLLDKFkuskDDBt
 RkoQmoutBcaCLCILg7++06lFIZfVqzr1LucOGPyb9b0jGOGbc/l4FTpLTdw7rp+7
 crzM7VArnEJa4AIk5h1L+RlkLty5scPnqSjY07YgUc/sZGUyFGn9f5dg6yPSeTen
 jLgoWUPq+H2/QEGVP+yxctyZRV2xfGK0/voDif2QepcBkkiT3OQuYjbcPY46F2xw
 8vfDXCKUvQ2j0RrLbK1GAhHlouOr4VYcB/iJZzHF/w54n95Q3qHzhP80jaMVyQNO
 65Sj080Hay7HnC9V1w5uHLx7lLhBYbWapuMgb19iXScW/wmpbmbn+ugehVW0itP3
 CHqxahddwbHtv2UHWjEUUKcYVXLxFfkn0C3kifrWwOzMfYrQZAMza2sQxMaiknmA
 a1eeqe1Smxow4fjbzxzsuqcN10z6WpMxyRNtr0sE5YDSdHW2a5BVYDd/x5LZ8IL1
 OM7tay1c9NgEMXAoEmHW8H4mDTRrgNfxfco1EFUG31+snZaEFZiFKksxr4PL8jDn
 XKwS7bBJFjIXonykPX87Bh5341X4gfNNoeNrOJu5L1yODWczYrQ=
 =lu6V
 -----END PGP SIGNATURE-----

Merge tag 'efi-2019-10-rc4-3' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for v2019.10-rc4 (3)

This includes the patches from
Pull request for UEFI sub-system for v2019.10-rc4 (2)

Fix UEFI specification compliance issues in the simple network protocol:

* Correctly set and reset the interrupt status.
* Support filling the header in the Transmit() service.
* Correct the checking and setting of the network state.
* Implement the MCastIPtoMAC() service.
* Adjust the simple network protocol unit test.

Fix UEFI specification compliance issues in the protocol.

Fix UEFI specification compliance issues in the simple text output protocol:
* Avoid out of bounds cursor position.
* Do not set illegal screen mode.

Fix UEFI specification compliance issues in the  block IO protocol:
* Check parameters.
* Return correct status code if buffer is unaligned.

Refactor initialization of EFI memory in preparation of support for
> 3GB memory on x86.
This commit is contained in:
Tom Rini 2019-09-06 08:04:08 -04:00
commit 6128e61429
15 changed files with 411 additions and 103 deletions

View file

@ -5,5 +5,6 @@ CONFIG_DISTRO_DEFAULTS=y
CONFIG_FIT=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_CMD_BOOTEFI_SELFTEST=y
# CONFIG_CMD_MII is not set
CONFIG_OF_PRIOR_STAGE=y

View file

@ -6,5 +6,6 @@ CONFIG_DISTRO_DEFAULTS=y
CONFIG_FIT=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_CMD_BOOTEFI_SELFTEST=y
# CONFIG_CMD_MII is not set
CONFIG_OF_PRIOR_STAGE=y

View file

@ -6,5 +6,6 @@ CONFIG_DISTRO_DEFAULTS=y
CONFIG_FIT=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_CMD_BOOTEFI_SELFTEST=y
# CONFIG_CMD_MII is not set
CONFIG_OF_PRIOR_STAGE=y

View file

@ -7,5 +7,6 @@ CONFIG_DISTRO_DEFAULTS=y
CONFIG_FIT=y
CONFIG_DISPLAY_CPUINFO=y
CONFIG_DISPLAY_BOARDINFO=y
CONFIG_CMD_BOOTEFI_SELFTEST=y
# CONFIG_CMD_MII is not set
CONFIG_OF_PRIOR_STAGE=y

View file

@ -103,3 +103,36 @@ Block device driver
.. kernel-doc:: lib/efi_driver/efi_block_device.c
:internal:
Protocols
---------
Block IO protocol
~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_disk.c
:internal:
File protocol
~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_file.c
:internal:
Graphical output protocol
~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_gop.c
:internal:
Network protocols
~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_net.c
:internal:
Text IO protocols
~~~~~~~~~~~~~~~~~
.. kernel-doc:: lib/efi_loader/efi_console.c
:internal:

View file

@ -483,7 +483,7 @@ struct efi_device_path_cdrom_path {
struct efi_device_path dp;
u32 boot_entry;
u64 partition_start;
u64 partition_end;
u64 partition_size;
} __packed;
struct efi_device_path_file_path {
@ -1281,6 +1281,8 @@ struct efi_simple_network {
struct efi_mac_address *dest_addr, u16 *protocol);
struct efi_event *wait_for_packet;
struct efi_simple_network_mode *mode;
/* private fields */
u32 int_status;
};
#define EFI_PXE_BASE_CODE_PROTOCOL_GUID \

View file

@ -478,6 +478,10 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
/* Adds a range into the EFI memory map */
efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
bool overlap_only_ram);
/* Adds a conventional range into the EFI memory map */
efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end,
u64 ram_top);
/* Called by board init to initialize the EFI drivers */
efi_status_t efi_driver_init(void);
/* Called by board init to initialize the EFI memory map */

View file

@ -156,13 +156,14 @@ static efi_status_t EFIAPI efi_cout_output_string(
* Update the cursor position.
*
* The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
* and U000D. All other characters, including control characters
* U+0007 (BEL) and U+0009 (TAB), have to increase the column by one.
* and U000D. All other control characters are ignored. Any non-control
* character increase the column by one.
*/
for (p = string; *p; ++p) {
switch (*p) {
case '\b': /* U+0008, backspace */
con->cursor_column = max(0, con->cursor_column - 1);
if (con->cursor_column)
con->cursor_column--;
break;
case '\n': /* U+000A, newline */
con->cursor_column = 0;
@ -178,6 +179,8 @@ static efi_status_t EFIAPI efi_cout_output_string(
*/
break;
default:
/* Exclude control codes */
if (*p > 0x1f)
con->cursor_column++;
break;
}
@ -185,7 +188,12 @@ static efi_status_t EFIAPI efi_cout_output_string(
con->cursor_column = 0;
con->cursor_row++;
}
con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
/*
* When we exceed the row count the terminal will scroll up one
* line. We have to adjust the cursor position.
*/
if (con->cursor_row >= mode->rows && con->cursor_row)
con->cursor_row--;
}
out:
@ -211,9 +219,9 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
/**
* query_console_serial() - query console size
*
* @rows pointer to return number of rows
* @columns pointer to return number of columns
* Returns 0 on success
* @rows: pointer to return number of rows
* @cols: pointer to return number of columns
* Returns: 0 on success
*/
static int query_console_serial(int *rows, int *cols)
{
@ -371,6 +379,10 @@ static efi_status_t EFIAPI efi_cout_set_mode(
if (mode_number >= efi_con_mode.max_mode)
return EFI_EXIT(EFI_UNSUPPORTED);
if (!efi_cout_modes[mode_number].present)
return EFI_EXIT(EFI_UNSUPPORTED);
efi_con_mode.mode = mode_number;
EFI_CALL(efi_cout_clear_screen(this));
@ -452,7 +464,7 @@ struct efi_simple_text_output_protocol efi_con_out = {
* struct efi_cin_notify_function - registered console input notify function
*
* @link: link to list
* @data: key to notify
* @key: key to notify
* @function: function to call
*/
struct efi_cin_notify_function {
@ -470,6 +482,7 @@ static LIST_HEAD(cin_notify_functions);
* set_shift_mask() - set shift mask
*
* @mod: Xterm shift mask
* @key_state: receives the state of the shift, alt, control, and logo keys
*/
void set_shift_mask(int mod, struct efi_key_state *key_state)
{
@ -492,7 +505,7 @@ void set_shift_mask(int mod, struct efi_key_state *key_state)
*
* This gets called when we have already parsed CSI.
*
* @modifiers: bit mask (shift, alt, ctrl)
* @key_state: receives the state of the shift, alt, control, and logo keys
* @return: the unmodified code
*/
static int analyze_modifiers(struct efi_key_state *key_state)

View file

@ -665,7 +665,7 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
cddp->dp.length = sizeof(*cddp);
cddp->partition_start = info.start;
cddp->partition_end = info.size;
cddp->partition_size = info.size;
buf = &cddp[1];
} else {

View file

@ -60,9 +60,18 @@ static char *dp_hardware(char *s, struct efi_device_path *dp)
break;
}
case DEVICE_PATH_SUB_TYPE_VENDOR: {
int i, n;
struct efi_device_path_vendor *vdp =
(struct efi_device_path_vendor *)dp;
s += sprintf(s, "VenHw(%pUl)", &vdp->guid);
s += sprintf(s, "VenHw(%pUl", &vdp->guid);
n = (int)vdp->dp.length - sizeof(struct efi_device_path_vendor);
if (n > 0) {
s += sprintf(s, ",");
for (i = 0; i < n; ++i)
s += sprintf(s, "%02x", vdp->vendor_data[i]);
}
s += sprintf(s, ")");
break;
}
default:
@ -115,17 +124,16 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
break;
}
case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
int i, n = sizeof(struct efi_mac_addr);
struct efi_device_path_mac_addr *mdp =
(struct efi_device_path_mac_addr *)dp;
if (mdp->if_type != 0 && mdp->if_type != 1)
break;
s += sprintf(s, "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
mdp->mac.addr[0], mdp->mac.addr[1],
mdp->mac.addr[2], mdp->mac.addr[3],
mdp->mac.addr[4], mdp->mac.addr[5],
mdp->if_type);
if (mdp->if_type <= 1)
n = 6;
s += sprintf(s, "MAC(");
for (i = 0; i < n; ++i)
s += sprintf(s, "%02x", mdp->mac.addr[i]);
s += sprintf(s, ",%u)", mdp->if_type);
break;
}
@ -133,7 +141,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
struct efi_device_path_usb_class *ucdp =
(struct efi_device_path_usb_class *)dp;
s += sprintf(s, "USBClass(%x,%x,%x,%x,%x)",
s += sprintf(s, "UsbClass(0x%x,0x%x,0x%x,0x%x,0x%x)",
ucdp->vendor_id, ucdp->product_id,
ucdp->device_class, ucdp->device_subclass,
ucdp->device_protocol);
@ -206,7 +214,8 @@ static char *dp_media(char *s, struct efi_device_path *dp)
case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
struct efi_device_path_cdrom_path *cddp =
(struct efi_device_path_cdrom_path *)dp;
s += sprintf(s, "CDROM(0x%x)", cddp->boot_entry);
s += sprintf(s, "CDROM(%u,0x%llx,0x%llx)", cddp->boot_entry,
cddp->partition_start, cddp->partition_size);
break;
}
case DEVICE_PATH_SUB_TYPE_FILE_PATH: {

View file

@ -41,11 +41,26 @@ struct efi_disk_obj {
struct blk_desc *desc;
};
/**
* efi_disk_reset() - reset block device
*
* This function implements the Reset service of the EFI_BLOCK_IO_PROTOCOL.
*
* As U-Boot's block devices do not have a reset function simply return
* EFI_SUCCESS.
*
* See the Unified Extensible Firmware Interface (UEFI) specification for
* details.
*
* @this: pointer to the BLOCK_IO_PROTOCOL
* @extended_verification: extended verification
* Return: status code
*/
static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
char extended_verification)
{
EFI_ENTRY("%p, %x", this, extended_verification);
return EFI_EXIT(EFI_DEVICE_ERROR);
return EFI_EXIT(EFI_SUCCESS);
}
enum efi_disk_direction {
@ -69,12 +84,12 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
blocks = buffer_size / blksz;
lba += diskobj->offset;
debug("EFI: %s:%d blocks=%x lba=%llx blksz=%x dir=%d\n", __func__,
__LINE__, blocks, lba, blksz, direction);
EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
blocks, lba, blksz, direction);
/* We only support full block access */
if (buffer_size & (blksz - 1))
return EFI_DEVICE_ERROR;
return EFI_BAD_BUFFER_SIZE;
if (direction == EFI_DISK_READ)
n = blk_dread(desc, lba, blocks, buffer);
@ -84,7 +99,7 @@ static efi_status_t efi_disk_rw_blocks(struct efi_block_io *this,
/* We don't do interrupts, so check for timers cooperatively */
efi_timer_check();
debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
EFI_PRINT("n=%lx blocks=%x\n", n, blocks);
if (n != blocks)
return EFI_DEVICE_ERROR;
@ -99,6 +114,20 @@ static efi_status_t EFIAPI efi_disk_read_blocks(struct efi_block_io *this,
void *real_buffer = buffer;
efi_status_t r;
if (!this)
return EFI_INVALID_PARAMETER;
/* TODO: check for media changes */
if (media_id != this->media->media_id)
return EFI_MEDIA_CHANGED;
if (!this->media->media_present)
return EFI_NO_MEDIA;
/* media->io_align is a power of 2 */
if ((uintptr_t)buffer & (this->media->io_align - 1))
return EFI_INVALID_PARAMETER;
if (lba * this->media->block_size + buffer_size >
this->media->last_block * this->media->block_size)
return EFI_INVALID_PARAMETER;
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
r = efi_disk_read_blocks(this, media_id, lba,
@ -134,6 +163,22 @@ static efi_status_t EFIAPI efi_disk_write_blocks(struct efi_block_io *this,
void *real_buffer = buffer;
efi_status_t r;
if (!this)
return EFI_INVALID_PARAMETER;
if (this->media->read_only)
return EFI_WRITE_PROTECTED;
/* TODO: check for media changes */
if (media_id != this->media->media_id)
return EFI_MEDIA_CHANGED;
if (!this->media->media_present)
return EFI_NO_MEDIA;
/* media->io_align is a power of 2 */
if ((uintptr_t)buffer & (this->media->io_align - 1))
return EFI_INVALID_PARAMETER;
if (lba * this->media->block_size + buffer_size >
this->media->last_block * this->media->block_size)
return EFI_INVALID_PARAMETER;
#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
r = efi_disk_write_blocks(this, media_id, lba,
@ -288,6 +333,11 @@ static efi_status_t efi_disk_add_dev(
/* Fill in EFI IO Media info (for read/write callbacks) */
diskobj->media.removable_media = desc->removable;
diskobj->media.media_present = 1;
/*
* MediaID is just an arbitrary counter.
* We have to change it if the medium is removed or changed.
*/
diskobj->media.media_id = 1;
diskobj->media.block_size = desc->blksz;
diskobj->media.io_align = desc->blksz;
diskobj->media.last_block = desc->lba - offset;

View file

@ -319,7 +319,7 @@ static efi_status_t gop_blt_vid_to_buf(struct efi_gop *this,
* details.
*
* @this: the graphical output protocol
* @model_number: the mode to be set
* @mode_number: the mode to be set
* Return: status code
*/
static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)

View file

@ -655,35 +655,26 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
return EFI_SUCCESS;
}
__weak void efi_add_known_memory(void)
{
u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
int i;
/*
* ram_top is just outside mapped memory. So use an offset of one for
* mapping the sandbox address.
/**
* efi_add_conventional_memory_map() - add a RAM memory area to the map
*
* @ram_start: start address of a RAM memory area
* @ram_end: end address of a RAM memory area
* @ram_top: max address to be used as conventional memory
* Return: status code
*/
ram_top = (uintptr_t)map_sysmem(ram_top - 1, 0) + 1;
/* Fix for 32bit targets with ram_top at 4G */
if (!ram_top)
ram_top = 0x100000000ULL;
/* Add RAM */
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
u64 ram_end, ram_start, pages;
ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0);
ram_end = ram_start + gd->bd->bi_dram[i].size;
efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end,
u64 ram_top)
{
u64 pages;
/* Remove partial pages */
ram_end &= ~EFI_PAGE_MASK;
ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
if (ram_end <= ram_start) {
/* Invalid mapping, keep going. */
continue;
/* Invalid mapping */
return EFI_INVALID_PARAMETER;
}
pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
@ -708,6 +699,33 @@ __weak void efi_add_known_memory(void)
efi_add_memory_map(ram_top, pages,
EFI_BOOT_SERVICES_DATA, true);
}
return EFI_SUCCESS;
}
__weak void efi_add_known_memory(void)
{
u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
int i;
/*
* ram_top is just outside mapped memory. So use an offset of one for
* mapping the sandbox address.
*/
ram_top = (uintptr_t)map_sysmem(ram_top - 1, 0) + 1;
/* Fix for 32bit targets with ram_top at 4G */
if (!ram_top)
ram_top = 0x100000000ULL;
/* Add RAM */
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
u64 ram_end, ram_start;
ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0);
ram_end = ram_start + gd->bd->bi_dram[i].size;
efi_add_conventional_memory_map(ram_start, ram_end, ram_top);
}
}

View file

@ -1,8 +1,18 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* EFI application network access support
* Simple network protocol
* PXE base code protocol
*
* Copyright (c) 2016 Alexander Graf
*
* The simple network protocol has the following statuses and services
* to move between them:
*
* Start(): EfiSimpleNetworkStopped -> EfiSimpleNetworkStarted
* Initialize(): EfiSimpleNetworkStarted -> EfiSimpleNetworkInitialized
* Shutdown(): EfiSimpleNetworkInitialized -> EfiSimpleNetworkStarted
* Stop(): EfiSimpleNetworkStarted -> EfiSimpleNetworkStopped
* Reset(): EfiSimpleNetworkInitialized -> EfiSimpleNetworkInitialized
*/
#include <common.h>
@ -66,10 +76,13 @@ static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
goto out;
}
if (this->mode->state != EFI_NETWORK_STOPPED)
if (this->mode->state != EFI_NETWORK_STOPPED) {
ret = EFI_ALREADY_STARTED;
else
} else {
this->int_status = 0;
wait_for_packet->is_signaled = false;
this->mode->state = EFI_NETWORK_STARTED;
}
out:
return EFI_EXIT(ret);
}
@ -96,10 +109,13 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
goto out;
}
if (this->mode->state == EFI_NETWORK_STOPPED)
if (this->mode->state == EFI_NETWORK_STOPPED) {
ret = EFI_NOT_STARTED;
else
} else {
/* Disable hardware and put it into the reset state */
eth_halt();
this->mode->state = EFI_NETWORK_STOPPED;
}
out:
return EFI_EXIT(ret);
}
@ -130,6 +146,15 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
goto out;
}
switch (this->mode->state) {
case EFI_NETWORK_INITIALIZED:
case EFI_NETWORK_STARTED:
break;
default:
r = EFI_NOT_STARTED;
goto out;
}
/* Setup packet buffers */
net_init();
/* Disable hardware and put it into the reset state */
@ -144,6 +169,8 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
r = EFI_DEVICE_ERROR;
goto out;
} else {
this->int_status = 0;
wait_for_packet->is_signaled = false;
this->mode->state = EFI_NETWORK_INITIALIZED;
}
out:
@ -164,9 +191,31 @@ out:
static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
int extended_verification)
{
efi_status_t ret;
EFI_ENTRY("%p, %x", this, extended_verification);
return EFI_EXIT(EFI_CALL(efi_net_initialize(this, 0, 0)));
/* Check parameters */
if (!this) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
switch (this->mode->state) {
case EFI_NETWORK_INITIALIZED:
break;
case EFI_NETWORK_STOPPED:
ret = EFI_NOT_STARTED;
goto out;
default:
ret = EFI_DEVICE_ERROR;
goto out;
}
this->mode->state = EFI_NETWORK_STARTED;
ret = EFI_CALL(efi_net_initialize(this, 0, 0));
out:
return EFI_EXIT(ret);
}
/*
@ -191,8 +240,21 @@ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
goto out;
}
switch (this->mode->state) {
case EFI_NETWORK_INITIALIZED:
break;
case EFI_NETWORK_STOPPED:
ret = EFI_NOT_STARTED;
goto out;
default:
ret = EFI_DEVICE_ERROR;
goto out;
}
eth_halt();
this->mode->state = EFI_NETWORK_STOPPED;
this->int_status = 0;
wait_for_packet->is_signaled = false;
this->mode->state = EFI_NETWORK_STARTED;
out:
return EFI_EXIT(ret);
@ -270,7 +332,7 @@ static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
/*
* efi_net_mcastiptomac() - translate multicast IP address to MAC address
*
* This function implements the Statistics service of the
* This function implements the MCastIPtoMAC service of the
* EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
* (UEFI) specification for details.
*
@ -285,9 +347,49 @@ static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
struct efi_ip_address *ip,
struct efi_mac_address *mac)
{
efi_status_t ret = EFI_SUCCESS;
EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
return EFI_EXIT(EFI_INVALID_PARAMETER);
if (!this || !ip || !mac) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
if (ipv6) {
ret = EFI_UNSUPPORTED;
goto out;
}
/* Multi-cast addresses are in the range 224.0.0.0 - 239.255.255.255 */
if ((ip->ip_addr[0] & 0xf0) != 0xe0) {
ret = EFI_INVALID_PARAMETER;
goto out;
};
switch (this->mode->state) {
case EFI_NETWORK_INITIALIZED:
case EFI_NETWORK_STARTED:
break;
default:
ret = EFI_NOT_STARTED;
goto out;
}
memset(mac, 0, sizeof(struct efi_mac_address));
/*
* Copy lower 23 bits of IPv4 multi-cast address
* RFC 1112, RFC 7042 2.1.1.
*/
mac->mac_addr[0] = 0x01;
mac->mac_addr[1] = 0x00;
mac->mac_addr[2] = 0x5E;
mac->mac_addr[3] = ip->ip_addr[1] & 0x7F;
mac->mac_addr[4] = ip->ip_addr[2];
mac->mac_addr[5] = ip->ip_addr[3];
out:
return EFI_EXIT(ret);
}
/**
@ -297,7 +399,7 @@ static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
* Protocol. See the UEFI spec for details.
*
* @this: the instance of the Simple Network Protocol
* @readwrite: true for read, false for write
* @read_write: true for read, false for write
* @offset: offset in NVRAM
* @buffer_size: size of buffer
* @buffer: buffer
@ -350,10 +452,8 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
}
if (int_status) {
/* We send packets synchronously, so nothing is outstanding */
*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
if (new_rx_packet)
*int_status |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
*int_status = this->int_status;
this->int_status = 0;
}
if (txbuf)
*txbuf = new_tx_packet;
@ -404,15 +504,33 @@ static efi_status_t EFIAPI efi_net_transmit
goto out;
}
if (header_size) {
/*
* TODO: We would need to create the header
* if header_size != 0
*/
ret = EFI_UNSUPPORTED;
/* At least the IP header has to fit into the buffer */
if (buffer_size < this->mode->media_header_size) {
ret = EFI_BUFFER_TOO_SMALL;
goto out;
}
/*
* TODO:
* Support VLANs. Use net_set_ether() for copying the header. Use a
* U_BOOT_ENV_CALLBACK to update the media header size.
*/
if (header_size) {
struct ethernet_hdr *header = buffer;
if (!dest_addr || !protocol ||
header_size != this->mode->media_header_size) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
if (!src_addr)
src_addr = &this->mode->current_address;
memcpy(header->et_dest, dest_addr, ARP_HLEN);
memcpy(header->et_src, src_addr, ARP_HLEN);
header->et_protlen = htons(*protocol);
}
switch (this->mode->state) {
case EFI_NETWORK_STOPPED:
ret = EFI_NOT_STARTED;
@ -429,7 +547,7 @@ static efi_status_t EFIAPI efi_net_transmit
net_send_packet(transmit_buffer, buffer_size);
new_tx_packet = buffer;
this->int_status |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
out:
return EFI_EXIT(ret);
}
@ -487,12 +605,6 @@ static efi_status_t EFIAPI efi_net_receive
ret = EFI_NOT_READY;
goto out;
}
/* Check that we at least received an Ethernet header */
if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
new_rx_packet = false;
ret = EFI_NOT_READY;
goto out;
}
/* Fill export parameters */
eth_hdr = (struct ethernet_hdr *)net_rx_packet;
protlen = ntohs(eth_hdr->et_protlen);
@ -517,7 +629,8 @@ static efi_status_t EFIAPI efi_net_receive
/* Copy packet */
memcpy(buffer, net_rx_packet, net_rx_packet_len);
*buffer_size = net_rx_packet_len;
new_rx_packet = false;
new_rx_packet = 0;
this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
out:
return EFI_EXIT(ret);
}
@ -526,6 +639,9 @@ out:
* efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
*
* This function is called by dhcp_handler().
*
* @pkt: packet received by dhcp_handler()
* @len: length of the packet received
*/
void efi_net_set_dhcp_ack(void *pkt, int len)
{
@ -548,7 +664,6 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
static void efi_net_push(void *pkt, int len)
{
new_rx_packet = true;
wait_for_packet->is_signaled = true;
}
/**
@ -556,8 +671,8 @@ static void efi_net_push(void *pkt, int len)
*
* This notification function is called in every timer cycle.
*
* @event the event for which this notification function is registered
* @context event context - not used in this function
* @event: the event for which this notification function is registered
* @context: event context - not used in this function
*/
static void EFIAPI efi_network_timer_notify(struct efi_event *event,
void *context)
@ -577,6 +692,17 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event,
push_packet = efi_net_push;
eth_rx();
push_packet = NULL;
if (new_rx_packet) {
/* Check that we at least received an Ethernet header */
if (net_rx_packet_len >=
sizeof(struct ethernet_hdr)) {
this->int_status |=
EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
wait_for_packet->is_signaled = true;
} else {
new_rx_packet = 0;
}
}
}
out:
EFI_EXIT(EFI_SUCCESS);
@ -751,9 +877,10 @@ efi_status_t efi_net_register(void)
netobj->net.transmit = efi_net_transmit;
netobj->net.receive = efi_net_receive;
netobj->net.mode = &netobj->net_mode;
netobj->net_mode.state = EFI_NETWORK_STARTED;
netobj->net_mode.state = EFI_NETWORK_STOPPED;
memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
netobj->net_mode.hwaddr_size = ARP_HLEN;
netobj->net_mode.media_header_size = ETHER_HDR_SIZE;
netobj->net_mode.max_packet_size = PKTSIZE;
netobj->net_mode.if_type = ARP_ETHER;

View file

@ -228,6 +228,26 @@ static int setup(const efi_handle_t handle,
efi_st_error("WaitForPacket event missing\n");
return EFI_ST_FAILURE;
}
if (net->mode->state == EFI_NETWORK_INITIALIZED) {
/*
* Shut down network adapter.
*/
ret = net->shutdown(net);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to shut down network adapter\n");
return EFI_ST_FAILURE;
}
}
if (net->mode->state == EFI_NETWORK_STARTED) {
/*
* Stop network adapter.
*/
ret = net->stop(net);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to stop network adapter\n");
return EFI_ST_FAILURE;
}
}
/*
* Start network adapter.
*/
@ -236,6 +256,10 @@ static int setup(const efi_handle_t handle,
efi_st_error("Failed to start network adapter\n");
return EFI_ST_FAILURE;
}
if (net->mode->state != EFI_NETWORK_STARTED) {
efi_st_error("Failed to start network adapter\n");
return EFI_ST_FAILURE;
}
/*
* Initialize network adapter.
*/
@ -244,6 +268,10 @@ static int setup(const efi_handle_t handle,
efi_st_error("Failed to initialize network adapter\n");
return EFI_ST_FAILURE;
}
if (net->mode->state != EFI_NETWORK_INITIALIZED) {
efi_st_error("Failed to initialize network adapter\n");
return EFI_ST_FAILURE;
}
return EFI_ST_SUCCESS;
}
@ -268,6 +296,7 @@ static int execute(void)
struct efi_mac_address destaddr;
size_t buffer_size;
u8 *addr;
/*
* The timeout is to occur after 10 s.
*/
@ -298,6 +327,8 @@ static int execute(void)
events[0] = timer;
events[1] = net->wait_for_packet;
for (;;) {
u32 int_status;
/*
* Wait for packet to be received or timer event.
*/
@ -323,7 +354,16 @@ static int execute(void)
* Receive packet
*/
buffer_size = sizeof(buffer);
net->receive(net, NULL, &buffer_size, &buffer,
ret = net->get_status(net, &int_status, NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to get status");
return EFI_ST_FAILURE;
}
if (!(int_status & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT)) {
efi_st_error("RX interrupt not set");
return EFI_ST_FAILURE;
}
ret = net->receive(net, NULL, &buffer_size, &buffer,
&srcaddr, &destaddr, NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to receive packet");
@ -399,6 +439,18 @@ static int teardown(void)
}
}
if (net) {
/*
* Shut down network adapter.
*/
ret = net->shutdown(net);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to shut down network adapter\n");
exit_status = EFI_ST_FAILURE;
}
if (net->mode->state != EFI_NETWORK_STARTED) {
efi_st_error("Failed to shutdown network adapter\n");
return EFI_ST_FAILURE;
}
/*
* Stop network adapter.
*/
@ -407,13 +459,9 @@ static int teardown(void)
efi_st_error("Failed to stop network adapter\n");
exit_status = EFI_ST_FAILURE;
}
/*
* Shut down network adapter.
*/
ret = net->shutdown(net);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to shut down network adapter\n");
exit_status = EFI_ST_FAILURE;
if (net->mode->state != EFI_NETWORK_STOPPED) {
efi_st_error("Failed to stop network adapter\n");
return EFI_ST_FAILURE;
}
}