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:
commit
6128e61429
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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 \
|
||||
|
@ -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 */
|
||||
|
@ -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,14 +179,21 @@ static efi_status_t EFIAPI efi_cout_output_string(
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
con->cursor_column++;
|
||||
/* Exclude control codes */
|
||||
if (*p > 0x1f)
|
||||
con->cursor_column++;
|
||||
break;
|
||||
}
|
||||
if (con->cursor_column >= mode->columns) {
|
||||
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)
|
||||
|
@ -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 {
|
||||
|
@ -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: {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -655,6 +655,54 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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 */
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
|
||||
|
||||
efi_add_memory_map(ram_start, pages,
|
||||
EFI_CONVENTIONAL_MEMORY, false);
|
||||
|
||||
/*
|
||||
* Boards may indicate to the U-Boot memory core that they
|
||||
* can not support memory above ram_top. Let's honor this
|
||||
* in the efi_loader subsystem too by declaring any memory
|
||||
* above ram_top as "already occupied by firmware".
|
||||
*/
|
||||
if (ram_top < ram_start) {
|
||||
/* ram_top is before this region, reserve all */
|
||||
efi_add_memory_map(ram_start, pages,
|
||||
EFI_BOOT_SERVICES_DATA, true);
|
||||
} else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
|
||||
/* ram_top is inside this region, reserve parts */
|
||||
pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
|
||||
|
||||
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;
|
||||
@ -672,42 +720,12 @@ __weak void efi_add_known_memory(void)
|
||||
|
||||
/* Add RAM */
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
u64 ram_end, ram_start, pages;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
|
||||
|
||||
efi_add_memory_map(ram_start, pages,
|
||||
EFI_CONVENTIONAL_MEMORY, false);
|
||||
|
||||
/*
|
||||
* Boards may indicate to the U-Boot memory core that they
|
||||
* can not support memory above ram_top. Let's honor this
|
||||
* in the efi_loader subsystem too by declaring any memory
|
||||
* above ram_top as "already occupied by firmware".
|
||||
*/
|
||||
if (ram_top < ram_start) {
|
||||
/* ram_top is before this region, reserve all */
|
||||
efi_add_memory_map(ram_start, pages,
|
||||
EFI_BOOT_SERVICES_DATA, true);
|
||||
} else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
|
||||
/* ram_top is inside this region, reserve parts */
|
||||
pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
|
||||
|
||||
efi_add_memory_map(ram_top, pages,
|
||||
EFI_BOOT_SERVICES_DATA, true);
|
||||
}
|
||||
efi_add_conventional_memory_map(ram_start, ram_end, ram_top);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* 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;
|
||||
|
||||
|
@ -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,8 +354,17 @@ static int execute(void)
|
||||
* Receive packet
|
||||
*/
|
||||
buffer_size = sizeof(buffer);
|
||||
net->receive(net, NULL, &buffer_size, &buffer,
|
||||
&srcaddr, &destaddr, NULL);
|
||||
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");
|
||||
return EFI_ST_FAILURE;
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user