mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 13:11:31 +00:00
Patch queue for efi - 2018-09-26
A lot of goodness in this release. We're *very* close to running the UEFI Shell and SCT natively. The only missing piece are HII protocols. - FAT write support (needed for SCT) - improved FAT directory support (needed for SCT) - RTC support with QEMU -M virt - Sandbox support (run UEFI binaries in Linux - yay) - Proper UTF-16 support - EFI_UNICODE_COLLATION_PROTOCOL support (for UEFI Shell) - EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL support (for UEFI Shell) - Fix window size determination - Fix Tegra by explicitly unmapping RAM - Clean up handle entanglement - Lots of generic code cleanup -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJbq6+cAAoJECszeR4D/txgV1cP+wZPVsY/kRDwCZ8PODOIyLW/ YWWX0CHOUNIXcvWyrQQVflRKE7IbsoPNU+PxOze/toBZvNGZofCqd/P0sT0kk8UU /aQ55+Hn8/N4etysKxhk2uszBuEXZsOdprNV3H7tO9vKsMHpImAdLvIyviYK0eCF WnNsmDVFv/W4M5IWDJrS7KqwTuLPYE5Xli9BW/O2qi8NOvpfyb4EEqdL7OHyHAxe 8zpzyaRXJkPcgPkJ6z3WZ+BmAuXSl5DsLWqfsnZJQzkXatRhT8PneRk787e+xK3A OEFarj5t/94T1KivxquM9iYi0NzwGWrrCfRzbQh5klV4Z/bRYHbGQ92j6iZyfnpj 0zvWrJCalDaUz310BKZDyzKYQnoDj5/iYaMJHtaG6zmkXCzM41kniGKxuy/3IpTB ozeFtH2AOwlAFZRIzQiazkyU0bizis2Y/K4xzOQczvVajdLW0DsLXL/hyqaFaGO2 3oVK350FXMHKa1UhpsG05aoQvyYq8N4YVEfOSdBKah8qhhMG8zZ2IaX5oheZJjr4 yPV8iaSj8trX3mI9clsnX9YT7qJdcS188JYSii+8SVpVH4VpgwvUSHfDqznn7JNz COue6rFo9sg55Le9OsoxUgaQ5GO4oz+5iGmfyBmOtQ3n83JxmP4CJK84Ykw2i9fi sxJR6aNtktsLhfYhlDO/ =ZuJG -----END PGP SIGNATURE----- Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot Patch queue for efi - 2018-09-26 A lot of goodness in this release. We're *very* close to running the UEFI Shell and SCT natively. The only missing piece are HII protocols. - FAT write support (needed for SCT) - improved FAT directory support (needed for SCT) - RTC support with QEMU -M virt - Sandbox support (run UEFI binaries in Linux - yay) - Proper UTF-16 support - EFI_UNICODE_COLLATION_PROTOCOL support (for UEFI Shell) - EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL support (for UEFI Shell) - Fix window size determination - Fix Tegra by explicitly unmapping RAM - Clean up handle entanglement - Lots of generic code cleanup [trini: Fixup merge conflict in include/configs/qemu-arm.h] Signed-off-by: Tom Rini <trini@konsulko.com>
This commit is contained in:
commit
0ae8dcfef7
81 changed files with 8086 additions and 1288 deletions
|
@ -383,12 +383,16 @@ T: git git://github.com/agraf/u-boot.git
|
|||
F: doc/README.uefi
|
||||
F: doc/README.iscsi
|
||||
F: Documentation/efi.rst
|
||||
F: include/capitalization.h
|
||||
F: include/cp1250.h
|
||||
F: include/cp437.h
|
||||
F: include/efi*
|
||||
F: include/pe.h
|
||||
F: include/asm-generic/pe.h
|
||||
F: lib/charset.c
|
||||
F: lib/efi*/
|
||||
F: test/py/tests/test_efi*
|
||||
F: test/unicode_ut.c
|
||||
F: cmd/bootefi.c
|
||||
F: tools/file2include.c
|
||||
|
||||
|
|
|
@ -747,6 +747,8 @@ config ARCH_QEMU
|
|||
select OF_CONTROL
|
||||
select PL01X_SERIAL
|
||||
imply CMD_DM
|
||||
imply DM_RTC
|
||||
imply RTC_PL031
|
||||
|
||||
config ARCH_RMOBILE
|
||||
bool "Renesas ARM SoCs"
|
||||
|
|
|
@ -835,7 +835,7 @@ int dram_init_banksize(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER)
|
||||
void efi_add_known_memory(void)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -135,7 +135,7 @@ remove_psci_node:
|
|||
|
||||
fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code,
|
||||
*boot_code_size);
|
||||
#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER)
|
||||
efi_add_memory_map((uintptr_t)&secondary_boot_code,
|
||||
ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT,
|
||||
EFI_RESERVED_MEMORY_TYPE, false);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <efi_loader.h>
|
||||
#include <errno.h>
|
||||
#include <ns16550.h>
|
||||
#include <usb.h>
|
||||
|
@ -210,6 +211,19 @@ int board_early_init_f(void)
|
|||
|
||||
int board_late_init(void)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER)
|
||||
if (gd->bd->bi_dram[1].start) {
|
||||
/*
|
||||
* Only bank 0 is below board_get_usable_ram_top(), so all of
|
||||
* bank 1 is not mapped by the U-Boot MMU configuration, and so
|
||||
* we must prevent EFI from using it.
|
||||
*/
|
||||
efi_add_memory_map(gd->bd->bi_dram[1].start,
|
||||
gd->bd->bi_dram[1].size >> EFI_PAGE_SHIFT,
|
||||
EFI_BOOT_SERVICES_DATA, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE)
|
||||
if (tegra_cpu_is_non_secure()) {
|
||||
printf("CPU is in NS mode\n");
|
||||
|
|
|
@ -57,14 +57,104 @@ int cleanup_before_linux_select(int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void *phys_to_virt(phys_addr_t paddr)
|
||||
/**
|
||||
* is_in_sandbox_mem() - Checks if a pointer is within sandbox's emulated DRAM
|
||||
*
|
||||
* This provides a way to check if a pointer is owned by sandbox (and is within
|
||||
* its RAM) or not. Sometimes pointers come from a test which conceptually runs
|
||||
* output sandbox, potentially with direct access to the C-library malloc()
|
||||
* function, or the sandbox stack (which is not actually within the emulated
|
||||
* DRAM.
|
||||
*
|
||||
* Such pointers obviously cannot be mapped into sandbox's DRAM, so we must
|
||||
* detect them an process them separately, by recording a mapping to a tag,
|
||||
* which we can use to map back to the pointer later.
|
||||
*
|
||||
* @ptr: Pointer to check
|
||||
* @return true if this is within sandbox emulated DRAM, false if not
|
||||
*/
|
||||
static bool is_in_sandbox_mem(const void *ptr)
|
||||
{
|
||||
return (void *)(gd->arch.ram_buf + paddr);
|
||||
return (const uint8_t *)ptr >= gd->arch.ram_buf &&
|
||||
(const uint8_t *)ptr < gd->arch.ram_buf + gd->ram_size;
|
||||
}
|
||||
|
||||
phys_addr_t virt_to_phys(void *vaddr)
|
||||
/**
|
||||
* phys_to_virt() - Converts a sandbox RAM address to a pointer
|
||||
*
|
||||
* Sandbox uses U-Boot addresses from 0 to the size of DRAM. These index into
|
||||
* the emulated DRAM buffer used by sandbox. This function converts such an
|
||||
* address to a pointer into this buffer, which can be used to access the
|
||||
* memory.
|
||||
*
|
||||
* If the address is outside this range, it is assumed to be a tag
|
||||
*/
|
||||
void *phys_to_virt(phys_addr_t paddr)
|
||||
{
|
||||
return (phys_addr_t)((uint8_t *)vaddr - gd->arch.ram_buf);
|
||||
struct sandbox_mapmem_entry *mentry;
|
||||
struct sandbox_state *state;
|
||||
|
||||
/* If the address is within emulated DRAM, calculate the value */
|
||||
if (paddr < gd->ram_size)
|
||||
return (void *)(gd->arch.ram_buf + paddr);
|
||||
|
||||
/*
|
||||
* Otherwise search out list of tags for the correct pointer previously
|
||||
* created by map_to_sysmem()
|
||||
*/
|
||||
state = state_get_current();
|
||||
list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
|
||||
if (mentry->tag == paddr) {
|
||||
printf("%s: Used map from %lx to %p\n", __func__,
|
||||
(ulong)paddr, mentry->ptr);
|
||||
return mentry->ptr;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s: Cannot map sandbox address %lx (SDRAM from 0 to %lx)\n",
|
||||
__func__, (ulong)paddr, (ulong)gd->ram_size);
|
||||
os_abort();
|
||||
|
||||
/* Not reached */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sandbox_mapmem_entry *find_tag(const void *ptr)
|
||||
{
|
||||
struct sandbox_mapmem_entry *mentry;
|
||||
struct sandbox_state *state = state_get_current();
|
||||
|
||||
list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
|
||||
if (mentry->ptr == ptr) {
|
||||
debug("%s: Used map from %p to %lx\n", __func__, ptr,
|
||||
mentry->tag);
|
||||
return mentry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
phys_addr_t virt_to_phys(void *ptr)
|
||||
{
|
||||
struct sandbox_mapmem_entry *mentry;
|
||||
|
||||
/*
|
||||
* If it is in emulated RAM, don't bother looking for a tag. Just
|
||||
* calculate the pointer using the provides offset into the RAM buffer.
|
||||
*/
|
||||
if (is_in_sandbox_mem(ptr))
|
||||
return (phys_addr_t)((uint8_t *)ptr - gd->arch.ram_buf);
|
||||
|
||||
mentry = find_tag(ptr);
|
||||
if (!mentry) {
|
||||
/* Abort so that gdb can be used here */
|
||||
printf("%s: Cannot map sandbox address %p (SDRAM from 0 to %lx)\n",
|
||||
__func__, ptr, (ulong)gd->ram_size);
|
||||
os_abort();
|
||||
}
|
||||
printf("%s: Used map from %p to %lx\n", __func__, ptr, mentry->tag);
|
||||
|
||||
return mentry->tag;
|
||||
}
|
||||
|
||||
void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
|
||||
|
@ -87,26 +177,59 @@ void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
|
|||
return phys_to_virt(paddr);
|
||||
}
|
||||
|
||||
void unmap_physmem(const void *vaddr, unsigned long flags)
|
||||
void unmap_physmem(const void *ptr, unsigned long flags)
|
||||
{
|
||||
#ifdef CONFIG_PCI
|
||||
if (map_dev) {
|
||||
pci_unmap_physmem(vaddr, map_len, map_dev);
|
||||
pci_unmap_physmem(ptr, map_len, map_dev);
|
||||
map_dev = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
phys_addr_t map_to_sysmem(const void *ptr)
|
||||
{
|
||||
struct sandbox_mapmem_entry *mentry;
|
||||
|
||||
/*
|
||||
* If it is in emulated RAM, don't bother creating a tag. Just return
|
||||
* the offset into the RAM buffer.
|
||||
*/
|
||||
if (is_in_sandbox_mem(ptr))
|
||||
return (u8 *)ptr - gd->arch.ram_buf;
|
||||
|
||||
/*
|
||||
* See if there is an existing tag with this pointer. If not, set up a
|
||||
* new one.
|
||||
*/
|
||||
mentry = find_tag(ptr);
|
||||
if (!mentry) {
|
||||
struct sandbox_state *state = state_get_current();
|
||||
|
||||
mentry = malloc(sizeof(*mentry));
|
||||
if (!mentry) {
|
||||
printf("%s: Error: Out of memory\n", __func__);
|
||||
os_exit(ENOMEM);
|
||||
}
|
||||
mentry->tag = state->next_tag++;
|
||||
mentry->ptr = (void *)ptr;
|
||||
list_add_tail(&mentry->sibling_node, &state->mapmem_head);
|
||||
debug("%s: Added map from %p to %lx\n", __func__, ptr,
|
||||
(ulong)mentry->tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the tag as the address to use. A later call to map_sysmem()
|
||||
* will return ptr
|
||||
*/
|
||||
return mentry->tag;
|
||||
}
|
||||
|
||||
void sandbox_set_enable_pci_map(int enable)
|
||||
{
|
||||
enable_pci_map = enable;
|
||||
}
|
||||
|
||||
phys_addr_t map_to_sysmem(const void *ptr)
|
||||
{
|
||||
return (u8 *)ptr - gd->arch.ram_buf;
|
||||
}
|
||||
|
||||
void flush_dcache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
|
@ -165,15 +288,3 @@ ulong timer_get_boot_us(void)
|
|||
|
||||
return (count - base_count) / 1000;
|
||||
}
|
||||
|
||||
int setjmp(jmp_buf jmp)
|
||||
{
|
||||
return os_setjmp((ulong *)jmp, sizeof(*jmp));
|
||||
}
|
||||
|
||||
void longjmp(jmp_buf jmp, int ret)
|
||||
{
|
||||
os_longjmp((ulong *)jmp, ret);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
|
|
@ -143,14 +143,16 @@ void os_tty_raw(int fd, bool allow_sigs)
|
|||
void *os_malloc(size_t length)
|
||||
{
|
||||
struct os_mem_hdr *hdr;
|
||||
int page_size = getpagesize();
|
||||
|
||||
hdr = mmap(NULL, length + sizeof(*hdr), PROT_READ | PROT_WRITE,
|
||||
hdr = mmap(NULL, length + page_size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (hdr == MAP_FAILED)
|
||||
return NULL;
|
||||
hdr->length = length;
|
||||
|
||||
return hdr + 1;
|
||||
return (void *)hdr + page_size;
|
||||
}
|
||||
|
||||
void os_free(void *ptr)
|
||||
|
@ -630,24 +632,7 @@ void os_localtime(struct rtc_time *rt)
|
|||
rt->tm_isdst = tm->tm_isdst;
|
||||
}
|
||||
|
||||
int os_setjmp(ulong *jmp, int size)
|
||||
void os_abort(void)
|
||||
{
|
||||
jmp_buf dummy;
|
||||
|
||||
/*
|
||||
* We cannot rely on the struct name that jmp_buf uses, so use a
|
||||
* local variable here
|
||||
*/
|
||||
if (size < sizeof(dummy)) {
|
||||
printf("setjmp: jmpbuf is too small (%d bytes, need %d)\n",
|
||||
size, sizeof(jmp_buf));
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
return setjmp((struct __jmp_buf_tag *)jmp);
|
||||
}
|
||||
|
||||
void os_longjmp(ulong *jmp, int ret)
|
||||
{
|
||||
longjmp((struct __jmp_buf_tag *)jmp, ret);
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -359,6 +359,14 @@ void state_reset_for_test(struct sandbox_state *state)
|
|||
|
||||
memset(&state->wdt, '\0', sizeof(state->wdt));
|
||||
memset(state->spi, '\0', sizeof(state->spi));
|
||||
|
||||
/*
|
||||
* Set up the memory tag list. Use the top of emulated SDRAM for the
|
||||
* first tag number, since that address offset is outside the legal
|
||||
* range, and can be assumed to be a tag.
|
||||
*/
|
||||
INIT_LIST_HEAD(&state->mapmem_head);
|
||||
state->next_tag = state->ram_size;
|
||||
}
|
||||
|
||||
int state_init(void)
|
||||
|
|
|
@ -24,6 +24,11 @@ struct jmp_buf_data {
|
|||
|
||||
typedef struct jmp_buf_data jmp_buf[1];
|
||||
|
||||
/*
|
||||
* We have to directly link with the system versions of
|
||||
* setjmp/longjmp, because setjmp must not return as otherwise
|
||||
* the stack may become invalid.
|
||||
*/
|
||||
int setjmp(jmp_buf jmp);
|
||||
__noreturn void longjmp(jmp_buf jmp, int ret);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <config.h>
|
||||
#include <sysreset.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/stringify.h>
|
||||
|
||||
/**
|
||||
|
@ -45,6 +46,23 @@ struct sandbox_wdt_info {
|
|||
bool running;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sandbox_mapmem_entry - maps pointers to/from U-Boot addresses
|
||||
*
|
||||
* When map_to_sysmem() is called with an address outside sandbox's emulated
|
||||
* RAM, a record is created with a tag that can be used to reference that
|
||||
* pointer. When map_sysmem() is called later with that tag, the pointer will
|
||||
* be returned, just as it would for a normal sandbox address.
|
||||
*
|
||||
* @tag: Address tag (a value which U-Boot uses to refer to the address)
|
||||
* @ptr: Associated pointer for that tag
|
||||
*/
|
||||
struct sandbox_mapmem_entry {
|
||||
ulong tag;
|
||||
void *ptr;
|
||||
struct list_head sibling_node;
|
||||
};
|
||||
|
||||
/* The complete state of the test system */
|
||||
struct sandbox_state {
|
||||
const char *cmd; /* Command to execute */
|
||||
|
@ -78,6 +96,9 @@ struct sandbox_state {
|
|||
|
||||
/* Information about Watchdog */
|
||||
struct sandbox_wdt_info wdt;
|
||||
|
||||
ulong next_tag; /* Next address tag to allocate */
|
||||
struct list_head mapmem_head; /* struct sandbox_mapmem_entry */
|
||||
};
|
||||
|
||||
/* Minimum space we guarantee in the state FDT when calling read/write*/
|
||||
|
|
|
@ -36,7 +36,7 @@ __weak unsigned int install_e820_map(unsigned int max_entries,
|
|||
return 4;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER)
|
||||
void efi_add_known_memory(void)
|
||||
{
|
||||
struct e820_entry e820[E820MAX];
|
||||
|
@ -72,4 +72,4 @@ void efi_add_known_memory(void)
|
|||
efi_add_memory_map(start, pages, type, false);
|
||||
}
|
||||
}
|
||||
#endif /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
|
||||
#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
|
||||
|
|
187
cmd/bootefi.c
187
cmd/bootefi.c
|
@ -49,6 +49,11 @@ efi_status_t efi_init_obj_list(void)
|
|||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* Initialize root node */
|
||||
ret = efi_root_node_register();
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* Initialize EFI driver uclass */
|
||||
ret = efi_driver_init();
|
||||
if (ret != EFI_SUCCESS)
|
||||
|
@ -116,32 +121,47 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info,
|
|||
{
|
||||
size_t size;
|
||||
const char *env = env_get(env_var);
|
||||
u16 *pos;
|
||||
|
||||
loaded_image_info->load_options = NULL;
|
||||
loaded_image_info->load_options_size = 0;
|
||||
if (!env)
|
||||
return;
|
||||
size = strlen(env) + 1;
|
||||
size = utf8_utf16_strlen(env) + 1;
|
||||
loaded_image_info->load_options = calloc(size, sizeof(u16));
|
||||
if (!loaded_image_info->load_options) {
|
||||
printf("ERROR: Out of memory\n");
|
||||
return;
|
||||
}
|
||||
utf8_to_utf16(loaded_image_info->load_options, (u8 *)env, size);
|
||||
pos = loaded_image_info->load_options;
|
||||
utf8_utf16_strcpy(&pos, env);
|
||||
loaded_image_info->load_options_size = size * 2;
|
||||
}
|
||||
|
||||
static void *copy_fdt(void *fdt)
|
||||
/**
|
||||
* copy_fdt() - Copy the device tree to a new location available to EFI
|
||||
*
|
||||
* The FDT is relocated into a suitable location within the EFI memory map.
|
||||
* An additional 12KB is added to the space in case the device tree needs to be
|
||||
* expanded later with fdt_open_into().
|
||||
*
|
||||
* @fdt_addr: On entry, address of start of FDT. On exit, address of relocated
|
||||
* FDT start
|
||||
* @fdt_sizep: Returns new size of FDT, including
|
||||
* @return new relocated address of FDT
|
||||
*/
|
||||
static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
|
||||
{
|
||||
u64 fdt_size = fdt_totalsize(fdt);
|
||||
unsigned long fdt_ram_start = -1L, fdt_pages;
|
||||
efi_status_t ret = 0;
|
||||
void *fdt, *new_fdt;
|
||||
u64 new_fdt_addr;
|
||||
void *new_fdt;
|
||||
uint fdt_size;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
u64 ram_start = gd->bd->bi_dram[i].start;
|
||||
u64 ram_size = gd->bd->bi_dram[i].size;
|
||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||
u64 ram_start = gd->bd->bi_dram[i].start;
|
||||
u64 ram_size = gd->bd->bi_dram[i].size;
|
||||
|
||||
if (!ram_size)
|
||||
continue;
|
||||
|
@ -154,30 +174,37 @@ static void *copy_fdt(void *fdt)
|
|||
* Give us at least 4KB of breathing room in case the device tree needs
|
||||
* to be expanded later. Round up to the nearest EFI page boundary.
|
||||
*/
|
||||
fdt_size += 4096;
|
||||
fdt = map_sysmem(*fdt_addrp, 0);
|
||||
fdt_size = fdt_totalsize(fdt);
|
||||
fdt_size += 4096 * 3;
|
||||
fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE);
|
||||
fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
|
||||
|
||||
/* Safe fdt location is at 128MB */
|
||||
new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size;
|
||||
if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_RUNTIME_SERVICES_DATA, fdt_pages,
|
||||
&new_fdt_addr) != EFI_SUCCESS) {
|
||||
/* Safe fdt location is at 127MB */
|
||||
new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size;
|
||||
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_RUNTIME_SERVICES_DATA, fdt_pages,
|
||||
&new_fdt_addr);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
/* If we can't put it there, put it somewhere */
|
||||
new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
|
||||
if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_RUNTIME_SERVICES_DATA, fdt_pages,
|
||||
&new_fdt_addr) != EFI_SUCCESS) {
|
||||
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
|
||||
EFI_RUNTIME_SERVICES_DATA, fdt_pages,
|
||||
&new_fdt_addr);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
printf("ERROR: Failed to reserve space for FDT\n");
|
||||
return NULL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
new_fdt = (void*)(ulong)new_fdt_addr;
|
||||
new_fdt = map_sysmem(new_fdt_addr, fdt_size);
|
||||
memcpy(new_fdt, fdt, fdt_totalsize(fdt));
|
||||
fdt_set_totalsize(new_fdt, fdt_size);
|
||||
|
||||
return new_fdt;
|
||||
*fdt_addrp = new_fdt_addr;
|
||||
*fdt_sizep = fdt_size;
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static efi_status_t efi_do_enter(
|
||||
|
@ -250,22 +277,27 @@ static void efi_carve_out_dt_rsv(void *fdt)
|
|||
}
|
||||
}
|
||||
|
||||
static efi_status_t efi_install_fdt(void *fdt)
|
||||
static efi_status_t efi_install_fdt(ulong fdt_addr)
|
||||
{
|
||||
bootm_headers_t img = { 0 };
|
||||
ulong fdt_pages, fdt_size, fdt_start, fdt_end;
|
||||
ulong fdt_pages, fdt_size, fdt_start;
|
||||
efi_status_t ret;
|
||||
void *fdt;
|
||||
|
||||
fdt = map_sysmem(fdt_addr, 0);
|
||||
if (fdt_check_header(fdt)) {
|
||||
printf("ERROR: invalid device tree\n");
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Prepare fdt for payload */
|
||||
fdt = copy_fdt(fdt);
|
||||
if (!fdt)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
ret = copy_fdt(&fdt_addr, &fdt_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
unmap_sysmem(fdt);
|
||||
fdt = map_sysmem(fdt_addr, 0);
|
||||
fdt_size = fdt_totalsize(fdt);
|
||||
if (image_setup_libfdt(&img, fdt, 0, NULL)) {
|
||||
printf("ERROR: failed to process device tree\n");
|
||||
return EFI_LOAD_ERROR;
|
||||
|
@ -279,30 +311,35 @@ static efi_status_t efi_install_fdt(void *fdt)
|
|||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
/* And reserve the space in the memory map */
|
||||
fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK;
|
||||
fdt_end = ((ulong)fdt) + fdt_totalsize(fdt);
|
||||
fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK;
|
||||
fdt_start = fdt_addr;
|
||||
fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
|
||||
/* Give a bootloader the chance to modify the device tree */
|
||||
fdt_pages += 2;
|
||||
|
||||
ret = efi_add_memory_map(fdt_start, fdt_pages,
|
||||
EFI_BOOT_SERVICES_DATA, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load an EFI payload into a newly allocated piece of memory, register all
|
||||
* EFI objects it would want to access and jump to it.
|
||||
/**
|
||||
* do_bootefi_exec() - execute EFI binary
|
||||
*
|
||||
* @efi: address of the binary
|
||||
* @device_path: path of the device from which the binary was loaded
|
||||
* @image_path: device path of the binary
|
||||
* Return: status code
|
||||
*
|
||||
* Load the EFI binary into a newly assigned memory unwinding the relocation
|
||||
* information, install the loaded image protocol, and call the binary.
|
||||
*/
|
||||
static efi_status_t do_bootefi_exec(void *efi,
|
||||
struct efi_device_path *device_path,
|
||||
struct efi_device_path *image_path)
|
||||
{
|
||||
struct efi_loaded_image loaded_image_info = {};
|
||||
struct efi_object loaded_image_info_obj = {};
|
||||
struct efi_object mem_obj = {};
|
||||
efi_handle_t mem_handle = NULL;
|
||||
struct efi_device_path *memdp = NULL;
|
||||
efi_status_t ret;
|
||||
struct efi_loaded_image_obj *image_handle = NULL;
|
||||
struct efi_loaded_image *loaded_image_info = NULL;
|
||||
|
||||
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
|
||||
struct efi_system_table *st);
|
||||
|
@ -310,16 +347,21 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
/*
|
||||
* Special case for efi payload not loaded from disk, such as
|
||||
* 'bootefi hello' or for example payload loaded directly into
|
||||
* memory via jtag/etc:
|
||||
* memory via jtag, etc:
|
||||
*/
|
||||
if (!device_path && !image_path) {
|
||||
printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
|
||||
/* actual addresses filled in after efi_load_pe() */
|
||||
memdp = efi_dp_from_mem(0, 0, 0);
|
||||
device_path = image_path = memdp;
|
||||
efi_add_handle(&mem_obj);
|
||||
|
||||
ret = efi_add_protocol(mem_obj.handle, &efi_guid_device_path,
|
||||
/*
|
||||
* Grub expects that the device path of the loaded image is
|
||||
* installed on a handle.
|
||||
*/
|
||||
ret = efi_create_handle(&mem_handle);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto exit;
|
||||
ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
|
||||
device_path);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto exit;
|
||||
|
@ -327,8 +369,10 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
assert(device_path && image_path);
|
||||
}
|
||||
|
||||
efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj,
|
||||
device_path, image_path);
|
||||
ret = efi_setup_loaded_image(device_path, image_path, &image_handle,
|
||||
&loaded_image_info);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
* gd lives in a fixed register which may get clobbered while we execute
|
||||
|
@ -337,9 +381,9 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
efi_save_gd();
|
||||
|
||||
/* Transfer environment variable bootargs as load options */
|
||||
set_load_options(&loaded_image_info, "bootargs");
|
||||
set_load_options(loaded_image_info, "bootargs");
|
||||
/* Load the EFI payload */
|
||||
entry = efi_load_pe(efi, &loaded_image_info);
|
||||
entry = efi_load_pe(image_handle, efi, loaded_image_info);
|
||||
if (!entry) {
|
||||
ret = EFI_LOAD_ERROR;
|
||||
goto exit;
|
||||
|
@ -347,10 +391,10 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
|
||||
if (memdp) {
|
||||
struct efi_device_path_memory *mdp = (void *)memdp;
|
||||
mdp->memory_type = loaded_image_info.image_code_type;
|
||||
mdp->start_address = (uintptr_t)loaded_image_info.image_base;
|
||||
mdp->memory_type = loaded_image_info->image_code_type;
|
||||
mdp->start_address = (uintptr_t)loaded_image_info->image_base;
|
||||
mdp->end_address = mdp->start_address +
|
||||
loaded_image_info.image_size;
|
||||
loaded_image_info->image_size;
|
||||
}
|
||||
|
||||
/* we don't support much: */
|
||||
|
@ -360,8 +404,8 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
/* Call our payload! */
|
||||
debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
|
||||
|
||||
if (setjmp(&loaded_image_info.exit_jmp)) {
|
||||
ret = loaded_image_info.exit_status;
|
||||
if (setjmp(&image_handle->exit_jmp)) {
|
||||
ret = image_handle->exit_status;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -373,7 +417,7 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
|
||||
/* Move into EL2 and keep running there */
|
||||
armv8_switch_to_el2((ulong)entry,
|
||||
(ulong)&loaded_image_info_obj.handle,
|
||||
(ulong)image_handle,
|
||||
(ulong)&systab, 0, (ulong)efi_run_in_el2,
|
||||
ES_TO_AARCH64);
|
||||
|
||||
|
@ -390,7 +434,7 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
secure_ram_addr(_do_nonsec_entry)(
|
||||
efi_run_in_hyp,
|
||||
(uintptr_t)entry,
|
||||
(uintptr_t)loaded_image_info_obj.handle,
|
||||
(uintptr_t)image_handle,
|
||||
(uintptr_t)&systab);
|
||||
|
||||
/* Should never reach here, efi exits with longjmp */
|
||||
|
@ -398,13 +442,14 @@ static efi_status_t do_bootefi_exec(void *efi,
|
|||
}
|
||||
#endif
|
||||
|
||||
ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry);
|
||||
ret = efi_do_enter(image_handle, &systab, entry);
|
||||
|
||||
exit:
|
||||
/* image has returned, loaded-image obj goes *poof*: */
|
||||
list_del(&loaded_image_info_obj.link);
|
||||
if (mem_obj.handle)
|
||||
list_del(&mem_obj.link);
|
||||
if (image_handle)
|
||||
efi_delete_handle(&image_handle->parent);
|
||||
if (mem_handle)
|
||||
efi_delete_handle(mem_handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -443,7 +488,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
char *saddr;
|
||||
efi_status_t r;
|
||||
unsigned long fdt_addr;
|
||||
void *fdt;
|
||||
|
||||
/* Allow unaligned memory access */
|
||||
allow_unaligned();
|
||||
|
@ -464,8 +508,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
if (!fdt_addr && *argv[2] != '0')
|
||||
return CMD_RET_USAGE;
|
||||
/* Install device tree */
|
||||
fdt = map_sysmem(fdt_addr, 0);
|
||||
r = efi_install_fdt(fdt);
|
||||
r = efi_install_fdt(fdt_addr);
|
||||
if (r != EFI_SUCCESS) {
|
||||
printf("ERROR: failed to install device tree\n");
|
||||
return CMD_RET_FAILURE;
|
||||
|
@ -489,8 +532,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
#endif
|
||||
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
|
||||
if (!strcmp(argv[1], "selftest")) {
|
||||
struct efi_loaded_image loaded_image_info = {};
|
||||
struct efi_object loaded_image_info_obj = {};
|
||||
struct efi_loaded_image_obj *image_handle;
|
||||
struct efi_loaded_image *loaded_image_info;
|
||||
|
||||
/* Construct a dummy device path. */
|
||||
bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
|
||||
|
@ -498,9 +541,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
(uintptr_t)&efi_selftest);
|
||||
bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
|
||||
|
||||
efi_setup_loaded_image(&loaded_image_info,
|
||||
&loaded_image_info_obj,
|
||||
bootefi_device_path, bootefi_image_path);
|
||||
r = efi_setup_loaded_image(bootefi_device_path,
|
||||
bootefi_image_path, &image_handle,
|
||||
&loaded_image_info);
|
||||
if (r != EFI_SUCCESS)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
/*
|
||||
* gd lives in a fixed register which may get clobbered while we
|
||||
* execute the payload. So save it here and restore it on every
|
||||
|
@ -508,12 +554,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
*/
|
||||
efi_save_gd();
|
||||
/* Transfer environment variable efi_selftest as load options */
|
||||
set_load_options(&loaded_image_info, "efi_selftest");
|
||||
set_load_options(loaded_image_info, "efi_selftest");
|
||||
/* Execute the test */
|
||||
r = efi_selftest(loaded_image_info_obj.handle, &systab);
|
||||
r = efi_selftest(image_handle, &systab);
|
||||
efi_restore_gd();
|
||||
free(loaded_image_info.load_options);
|
||||
list_del(&loaded_image_info_obj.link);
|
||||
free(loaded_image_info->load_options);
|
||||
efi_delete_handle(&image_handle->parent);
|
||||
return r != EFI_SUCCESS;
|
||||
} else
|
||||
#endif
|
||||
|
@ -575,6 +621,13 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
|
|||
char filename[32] = { 0 }; /* dp->str is u16[32] long */
|
||||
char *s;
|
||||
|
||||
/* efi_set_bootdev is typically called repeatedly, recover memory */
|
||||
efi_free_pool(bootefi_device_path);
|
||||
efi_free_pool(bootefi_image_path);
|
||||
/* If blk_get_device_part_str fails, avoid duplicate free. */
|
||||
bootefi_device_path = NULL;
|
||||
bootefi_image_path = NULL;
|
||||
|
||||
if (strcmp(dev, "Net")) {
|
||||
struct blk_desc *desc;
|
||||
disk_partition_t fs_partition;
|
||||
|
|
34
cmd/fat.c
34
cmd/fat.c
|
@ -104,6 +104,7 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag,
|
|||
int ret;
|
||||
unsigned long addr;
|
||||
unsigned long count;
|
||||
long offset;
|
||||
struct blk_desc *dev_desc = NULL;
|
||||
disk_partition_t info;
|
||||
int dev = 0;
|
||||
|
@ -126,9 +127,11 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag,
|
|||
}
|
||||
addr = simple_strtoul(argv[3], NULL, 16);
|
||||
count = (argc <= 5) ? 0 : simple_strtoul(argv[5], NULL, 16);
|
||||
/* offset should be a hex, but "-1" is allowed */
|
||||
offset = (argc <= 6) ? 0 : simple_strtol(argv[6], NULL, 16);
|
||||
|
||||
buf = map_sysmem(addr, count);
|
||||
ret = file_fat_write(argv[4], buf, 0, count, &size);
|
||||
ret = file_fat_write(argv[4], buf, offset, count, &size);
|
||||
unmap_sysmem(buf);
|
||||
if (ret < 0) {
|
||||
printf("\n** Unable to write \"%s\" from %s %d:%d **\n",
|
||||
|
@ -142,10 +145,35 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag,
|
|||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatwrite, 6, 0, do_fat_fswrite,
|
||||
fatwrite, 7, 0, do_fat_fswrite,
|
||||
"write file into a dos filesystem",
|
||||
"<interface> <dev[:part]> <addr> <filename> [<bytes>]\n"
|
||||
"<interface> <dev[:part]> <addr> <filename> [<bytes> [<offset>]]\n"
|
||||
" - write file 'filename' from the address 'addr' in RAM\n"
|
||||
" to 'dev' on 'interface'"
|
||||
);
|
||||
|
||||
static int do_fat_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
return do_rm(cmdtp, flag, argc, argv, FS_TYPE_FAT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatrm, 4, 1, do_fat_rm,
|
||||
"delete a file",
|
||||
"<interface> [<dev[:part]>] <filename>\n"
|
||||
" - delete a file from 'dev' on 'interface'"
|
||||
);
|
||||
|
||||
static int do_fat_mkdir(cmd_tbl_t *cmdtp, int flag, int argc,
|
||||
char * const argv[])
|
||||
{
|
||||
return do_mkdir(cmdtp, flag, argc, argv, FS_TYPE_FAT);
|
||||
}
|
||||
|
||||
U_BOOT_CMD(
|
||||
fatmkdir, 4, 1, do_fat_mkdir,
|
||||
"create a directory",
|
||||
"<interface> [<dev[:part]>] <directory>\n"
|
||||
" - create a directory in 'dev' on 'interface'"
|
||||
);
|
||||
#endif
|
||||
|
|
|
@ -262,7 +262,7 @@ int bootm_find_images(int flag, int argc, char * const argv[])
|
|||
puts("Could not find a valid device tree\n");
|
||||
return 1;
|
||||
}
|
||||
set_working_fdt_addr((ulong)images.ft_addr);
|
||||
set_working_fdt_addr(map_to_sysmem(images.ft_addr));
|
||||
#endif
|
||||
|
||||
#if IMAGE_ENABLE_FIT
|
||||
|
|
|
@ -193,7 +193,7 @@ int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
|
|||
*of_flat_tree = of_start;
|
||||
*of_size = of_len;
|
||||
|
||||
set_working_fdt_addr((ulong)*of_flat_tree);
|
||||
set_working_fdt_addr(map_to_sysmem(*of_flat_tree));
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
|
@ -8,6 +8,7 @@ CONFIG_DISTRO_DEFAULTS=y
|
|||
CONFIG_NR_DRAM_BANKS=1
|
||||
# CONFIG_DISPLAY_CPUINFO is not set
|
||||
# CONFIG_DISPLAY_BOARDINFO is not set
|
||||
CONFIG_CMD_BOOTEFI_SELFTEST=y
|
||||
CONFIG_CMD_PCI=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_DATE=y
|
||||
|
|
|
@ -8,6 +8,7 @@ CONFIG_DISTRO_DEFAULTS=y
|
|||
CONFIG_NR_DRAM_BANKS=1
|
||||
# CONFIG_DISPLAY_CPUINFO is not set
|
||||
# CONFIG_DISPLAY_BOARDINFO is not set
|
||||
CONFIG_CMD_BOOTEFI_SELFTEST=y
|
||||
CONFIG_CMD_PCI=y
|
||||
CONFIG_CMD_USB=y
|
||||
CONFIG_CMD_DATE=y
|
||||
|
|
|
@ -23,6 +23,7 @@ CONFIG_DISPLAY_BOARDINFO_LATE=y
|
|||
CONFIG_CMD_CPU=y
|
||||
CONFIG_CMD_LICENSE=y
|
||||
CONFIG_CMD_BOOTZ=y
|
||||
CONFIG_CMD_BOOTEFI_SELFTEST=y
|
||||
# CONFIG_CMD_ELF is not set
|
||||
CONFIG_CMD_ASKENV=y
|
||||
CONFIG_CMD_GREPENV=y
|
||||
|
|
|
@ -39,3 +39,4 @@ CONFIG_PHY_MICREL=y
|
|||
CONFIG_MII=y
|
||||
CONFIG_DM_SERIAL=y
|
||||
CONFIG_FSL_LPUART=y
|
||||
# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
|
||||
|
|
|
@ -39,3 +39,4 @@ CONFIG_PHY_MICREL=y
|
|||
CONFIG_MII=y
|
||||
CONFIG_DM_SERIAL=y
|
||||
CONFIG_FSL_LPUART=y
|
||||
# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <rtc.h>
|
||||
|
||||
#if defined(CONFIG_CMD_DATE)
|
||||
|
||||
#ifndef CONFIG_SYS_RTC_PL031_BASE
|
||||
#error CONFIG_SYS_RTC_PL031_BASE is not defined!
|
||||
#endif
|
||||
#include <asm/io.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
/*
|
||||
* Register definitions
|
||||
|
@ -30,78 +28,114 @@
|
|||
|
||||
#define RTC_CR_START (1 << 0)
|
||||
|
||||
#define RTC_WRITE_REG(addr, val) \
|
||||
(*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)) = (val))
|
||||
#define RTC_READ_REG(addr) \
|
||||
(*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)))
|
||||
struct pl031_platdata {
|
||||
phys_addr_t base;
|
||||
};
|
||||
|
||||
static int pl031_initted = 0;
|
||||
|
||||
/* Enable RTC Start in Control register*/
|
||||
void rtc_init(void)
|
||||
static inline u32 pl031_read_reg(struct udevice *dev, int reg)
|
||||
{
|
||||
RTC_WRITE_REG(RTC_CR, RTC_CR_START);
|
||||
struct pl031_platdata *pdata = dev_get_platdata(dev);
|
||||
|
||||
pl031_initted = 1;
|
||||
return readl(pdata->base + reg);
|
||||
}
|
||||
|
||||
static inline u32 pl031_write_reg(struct udevice *dev, int reg, u32 value)
|
||||
{
|
||||
struct pl031_platdata *pdata = dev_get_platdata(dev);
|
||||
|
||||
return writel(value, pdata->base + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the RTC. We set the date back to 1970-01-01.
|
||||
* Probe RTC device
|
||||
*/
|
||||
void rtc_reset(void)
|
||||
static int pl031_probe(struct udevice *dev)
|
||||
{
|
||||
RTC_WRITE_REG(RTC_LR, 0x00);
|
||||
if(!pl031_initted)
|
||||
rtc_init();
|
||||
}
|
||||
/* Enable RTC Start in Control register*/
|
||||
pl031_write_reg(dev, RTC_CR, RTC_CR_START);
|
||||
|
||||
/*
|
||||
* Set the RTC
|
||||
*/
|
||||
int rtc_set(struct rtc_time *tmp)
|
||||
{
|
||||
unsigned long tim;
|
||||
|
||||
if(!pl031_initted)
|
||||
rtc_init();
|
||||
|
||||
if (tmp == NULL) {
|
||||
puts("Error setting the date/time\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate number of seconds this incoming time represents */
|
||||
tim = rtc_mktime(tmp);
|
||||
|
||||
RTC_WRITE_REG(RTC_LR, tim);
|
||||
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the current time from the RTC
|
||||
*/
|
||||
int rtc_get(struct rtc_time *tmp)
|
||||
static int pl031_get(struct udevice *dev, struct rtc_time *tm)
|
||||
{
|
||||
ulong tim;
|
||||
unsigned long tim;
|
||||
|
||||
if(!pl031_initted)
|
||||
rtc_init();
|
||||
if (!tm)
|
||||
return -EINVAL;
|
||||
|
||||
if (tmp == NULL) {
|
||||
puts("Error getting the date/time\n");
|
||||
return -1;
|
||||
}
|
||||
tim = pl031_read_reg(dev, RTC_DR);
|
||||
|
||||
tim = RTC_READ_REG(RTC_DR);
|
||||
rtc_to_tm(tim, tm);
|
||||
|
||||
rtc_to_tm(tim, tmp);
|
||||
|
||||
debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
|
||||
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
|
||||
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Set the RTC
|
||||
*/
|
||||
static int pl031_set(struct udevice *dev, const struct rtc_time *tm)
|
||||
{
|
||||
unsigned long tim;
|
||||
|
||||
if (!tm)
|
||||
return -EINVAL;
|
||||
|
||||
debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
|
||||
tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
/* Calculate number of seconds this incoming time represents */
|
||||
tim = rtc_mktime(tm);
|
||||
|
||||
pl031_write_reg(dev, RTC_LR, tim);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the RTC. We set the date back to 1970-01-01.
|
||||
*/
|
||||
static int pl031_reset(struct udevice *dev)
|
||||
{
|
||||
pl031_write_reg(dev, RTC_LR, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_ops pl031_ops = {
|
||||
.get = pl031_get,
|
||||
.set = pl031_set,
|
||||
.reset = pl031_reset,
|
||||
};
|
||||
|
||||
static const struct udevice_id pl031_ids[] = {
|
||||
{ .compatible = "arm,pl031" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int pl031_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct pl031_platdata *pdata = dev_get_platdata(dev);
|
||||
|
||||
pdata->base = dev_read_addr(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(rtc_pl031) = {
|
||||
.name = "rtc-pl031",
|
||||
.id = UCLASS_RTC,
|
||||
.of_match = pl031_ids,
|
||||
.probe = pl031_probe,
|
||||
.ofdata_to_platdata = pl031_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct pl031_platdata),
|
||||
.ops = &pl031_ops,
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
/* Information about the efi console */
|
||||
struct serial_efi_priv {
|
||||
struct efi_simple_input_interface *con_in;
|
||||
struct efi_simple_text_input_protocol *con_in;
|
||||
struct efi_simple_text_output_protocol *con_out;
|
||||
struct efi_input_key key;
|
||||
bool have_key;
|
||||
|
|
|
@ -213,6 +213,14 @@ static void vidconsole_escape_char(struct udevice *dev, char ch)
|
|||
s++; /* ; */
|
||||
s = parsenum(s, &col);
|
||||
|
||||
/*
|
||||
* Ensure we stay in the bounds of the screen.
|
||||
*/
|
||||
if (row >= priv->rows)
|
||||
row = priv->rows - 1;
|
||||
if (col >= priv->cols)
|
||||
col = priv->cols - 1;
|
||||
|
||||
priv->ycur = row * priv->y_charsize;
|
||||
priv->xcur_frac = priv->xstart_frac +
|
||||
VID_TO_POS(col * priv->x_charsize);
|
||||
|
|
67
fs/fat/fat.c
67
fs/fat/fat.c
|
@ -260,7 +260,7 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, unsigned long size)
|
|||
if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
|
||||
ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
|
||||
|
||||
printf("FAT: Misaligned buffer address (%p)\n", buffer);
|
||||
debug("FAT: Misaligned buffer address (%p)\n", buffer);
|
||||
|
||||
while (size >= mydata->sect_size) {
|
||||
ret = disk_read(startsect++, 1, tmpbuf);
|
||||
|
@ -464,15 +464,6 @@ static __u8 mkcksum(const char name[8], const char ext[3])
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO these should go away once fat_write is reworked to use the
|
||||
* directory iterator
|
||||
*/
|
||||
__u8 get_dentfromdir_block[MAX_CLUSTSIZE]
|
||||
__aligned(ARCH_DMA_MINALIGN);
|
||||
__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
|
||||
__aligned(ARCH_DMA_MINALIGN);
|
||||
|
||||
/*
|
||||
* Read boot sector and volume info from a FAT filesystem
|
||||
*/
|
||||
|
@ -558,10 +549,17 @@ static int get_fs_info(fsdata *mydata)
|
|||
|
||||
if (mydata->fatsize == 32) {
|
||||
mydata->fatlength = bs.fat32_length;
|
||||
mydata->total_sect = bs.total_sect;
|
||||
} else {
|
||||
mydata->fatlength = bs.fat_length;
|
||||
mydata->total_sect = (bs.sectors[1] << 8) + bs.sectors[0];
|
||||
if (!mydata->total_sect)
|
||||
mydata->total_sect = bs.total_sect;
|
||||
}
|
||||
if (!mydata->total_sect) /* unlikely */
|
||||
mydata->total_sect = (u32)cur_part_info.size;
|
||||
|
||||
mydata->fats = bs.fats;
|
||||
mydata->fat_sect = bs.reserved;
|
||||
|
||||
mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats;
|
||||
|
@ -633,7 +631,9 @@ static int get_fs_info(fsdata *mydata)
|
|||
|
||||
typedef struct {
|
||||
fsdata *fsdata; /* filesystem parameters */
|
||||
unsigned start_clust; /* first cluster */
|
||||
unsigned clust; /* current cluster */
|
||||
unsigned next_clust; /* next cluster if remaining == 0 */
|
||||
int last_cluster; /* set once we've read last cluster */
|
||||
int is_root; /* is iterator at root directory */
|
||||
int remaining; /* remaining dent's in current cluster */
|
||||
|
@ -664,7 +664,9 @@ static int fat_itr_root(fat_itr *itr, fsdata *fsdata)
|
|||
return -ENXIO;
|
||||
|
||||
itr->fsdata = fsdata;
|
||||
itr->start_clust = 0;
|
||||
itr->clust = fsdata->root_cluster;
|
||||
itr->next_clust = fsdata->root_cluster;
|
||||
itr->dent = NULL;
|
||||
itr->remaining = 0;
|
||||
itr->last_cluster = 0;
|
||||
|
@ -698,11 +700,14 @@ static void fat_itr_child(fat_itr *itr, fat_itr *parent)
|
|||
assert(fat_itr_isdir(parent));
|
||||
|
||||
itr->fsdata = parent->fsdata;
|
||||
itr->start_clust = clustnum;
|
||||
if (clustnum > 0) {
|
||||
itr->clust = clustnum;
|
||||
itr->next_clust = clustnum;
|
||||
itr->is_root = 0;
|
||||
} else {
|
||||
itr->clust = parent->fsdata->root_cluster;
|
||||
itr->next_clust = parent->fsdata->root_cluster;
|
||||
itr->is_root = 1;
|
||||
}
|
||||
itr->dent = NULL;
|
||||
|
@ -720,7 +725,7 @@ static void *next_cluster(fat_itr *itr)
|
|||
if (itr->last_cluster)
|
||||
return NULL;
|
||||
|
||||
sect = clust_to_sect(itr->fsdata, itr->clust);
|
||||
sect = clust_to_sect(itr->fsdata, itr->next_clust);
|
||||
|
||||
debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
|
||||
sect, itr->fsdata->clust_size, DIRENTSPERBLOCK);
|
||||
|
@ -741,18 +746,19 @@ static void *next_cluster(fat_itr *itr)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
itr->clust = itr->next_clust;
|
||||
if (itr->is_root && itr->fsdata->fatsize != 32) {
|
||||
itr->clust++;
|
||||
sect = clust_to_sect(itr->fsdata, itr->clust);
|
||||
itr->next_clust++;
|
||||
sect = clust_to_sect(itr->fsdata, itr->next_clust);
|
||||
if (sect - itr->fsdata->rootdir_sect >=
|
||||
itr->fsdata->rootdir_size) {
|
||||
debug("cursect: 0x%x\n", itr->clust);
|
||||
debug("nextclust: 0x%x\n", itr->next_clust);
|
||||
itr->last_cluster = 1;
|
||||
}
|
||||
} else {
|
||||
itr->clust = get_fatent(itr->fsdata, itr->clust);
|
||||
if (CHECK_CLUST(itr->clust, itr->fsdata->fatsize)) {
|
||||
debug("cursect: 0x%x\n", itr->clust);
|
||||
itr->next_clust = get_fatent(itr->fsdata, itr->next_clust);
|
||||
if (CHECK_CLUST(itr->next_clust, itr->fsdata->fatsize)) {
|
||||
debug("nextclust: 0x%x\n", itr->next_clust);
|
||||
itr->last_cluster = 1;
|
||||
}
|
||||
}
|
||||
|
@ -768,8 +774,11 @@ static dir_entry *next_dent(fat_itr *itr)
|
|||
itr->fsdata->clust_size;
|
||||
|
||||
/* have we reached the last cluster? */
|
||||
if (!dent)
|
||||
if (!dent) {
|
||||
/* a sign for no more entries left */
|
||||
itr->dent = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
itr->remaining = nbytes / sizeof(dir_entry) - 1;
|
||||
itr->dent = dent;
|
||||
|
@ -924,6 +933,28 @@ static int fat_itr_resolve(fat_itr *itr, const char *path, unsigned type)
|
|||
while (next[0] && !ISDIRDELIM(next[0]))
|
||||
next++;
|
||||
|
||||
if (itr->is_root) {
|
||||
/* root dir doesn't have "." nor ".." */
|
||||
if ((((next - path) == 1) && !strncmp(path, ".", 1)) ||
|
||||
(((next - path) == 2) && !strncmp(path, "..", 2))) {
|
||||
/* point back to itself */
|
||||
itr->clust = itr->fsdata->root_cluster;
|
||||
itr->next_clust = itr->fsdata->root_cluster;
|
||||
itr->dent = NULL;
|
||||
itr->remaining = 0;
|
||||
itr->last_cluster = 0;
|
||||
|
||||
if (next[0] == 0) {
|
||||
if (type & TYPE_DIR)
|
||||
return 0;
|
||||
else
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return fat_itr_resolve(itr, next, type);
|
||||
}
|
||||
}
|
||||
|
||||
while (fat_itr_next(itr)) {
|
||||
int match = 0;
|
||||
unsigned n = max(strlen(itr->name), (size_t)(next - path));
|
||||
|
|
1267
fs/fat/fat_write.c
1267
fs/fat/fat_write.c
File diff suppressed because it is too large
Load diff
87
fs/fs.c
87
fs/fs.c
|
@ -105,6 +105,16 @@ static inline int fs_opendir_unsupported(const char *filename,
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
static inline int fs_unlink_unsupported(const char *filename)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int fs_mkdir_unsupported(const char *dirname)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct fstype_info {
|
||||
int fstype;
|
||||
char *name;
|
||||
|
@ -142,6 +152,8 @@ struct fstype_info {
|
|||
int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
|
||||
/* see fs_closedir() */
|
||||
void (*closedir)(struct fs_dir_stream *dirs);
|
||||
int (*unlink)(const char *filename);
|
||||
int (*mkdir)(const char *dirname);
|
||||
};
|
||||
|
||||
static struct fstype_info fstypes[] = {
|
||||
|
@ -158,8 +170,12 @@ static struct fstype_info fstypes[] = {
|
|||
.read = fat_read_file,
|
||||
#ifdef CONFIG_FAT_WRITE
|
||||
.write = file_fat_write,
|
||||
.unlink = fat_unlink,
|
||||
.mkdir = fat_mkdir,
|
||||
#else
|
||||
.write = fs_write_unsupported,
|
||||
.unlink = fs_unlink_unsupported,
|
||||
.mkdir = fs_mkdir_unsupported,
|
||||
#endif
|
||||
.uuid = fs_uuid_unsupported,
|
||||
.opendir = fat_opendir,
|
||||
|
@ -185,6 +201,8 @@ static struct fstype_info fstypes[] = {
|
|||
#endif
|
||||
.uuid = ext4fs_uuid,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
.unlink = fs_unlink_unsupported,
|
||||
.mkdir = fs_mkdir_unsupported,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_SANDBOX
|
||||
|
@ -201,6 +219,8 @@ static struct fstype_info fstypes[] = {
|
|||
.write = fs_write_sandbox,
|
||||
.uuid = fs_uuid_unsupported,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
.unlink = fs_unlink_unsupported,
|
||||
.mkdir = fs_mkdir_unsupported,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_CMD_UBIFS
|
||||
|
@ -217,6 +237,8 @@ static struct fstype_info fstypes[] = {
|
|||
.write = fs_write_unsupported,
|
||||
.uuid = fs_uuid_unsupported,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
.unlink = fs_unlink_unsupported,
|
||||
.mkdir = fs_mkdir_unsupported,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_FS_BTRFS
|
||||
|
@ -233,6 +255,8 @@ static struct fstype_info fstypes[] = {
|
|||
.write = fs_write_unsupported,
|
||||
.uuid = btrfs_uuid,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
.unlink = fs_unlink_unsupported,
|
||||
.mkdir = fs_mkdir_unsupported,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
|
@ -248,6 +272,8 @@ static struct fstype_info fstypes[] = {
|
|||
.write = fs_write_unsupported,
|
||||
.uuid = fs_uuid_unsupported,
|
||||
.opendir = fs_opendir_unsupported,
|
||||
.unlink = fs_unlink_unsupported,
|
||||
.mkdir = fs_mkdir_unsupported,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -497,6 +523,33 @@ void fs_closedir(struct fs_dir_stream *dirs)
|
|||
fs_close();
|
||||
}
|
||||
|
||||
int fs_unlink(const char *filename)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fstype_info *info = fs_get_info(fs_type);
|
||||
|
||||
ret = info->unlink(filename);
|
||||
|
||||
fs_type = FS_TYPE_ANY;
|
||||
fs_close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fs_mkdir(const char *dirname)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct fstype_info *info = fs_get_info(fs_type);
|
||||
|
||||
ret = info->mkdir(dirname);
|
||||
|
||||
fs_type = FS_TYPE_ANY;
|
||||
fs_close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
||||
int fstype)
|
||||
|
@ -700,3 +753,37 @@ int do_fs_type(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
||||
int fstype)
|
||||
{
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (fs_set_blk_dev(argv[1], argv[2], fstype))
|
||||
return 1;
|
||||
|
||||
if (fs_unlink(argv[3]))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
||||
int fstype)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (argc != 4)
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
if (fs_set_blk_dev(argv[1], argv[2], fstype))
|
||||
return 1;
|
||||
|
||||
ret = fs_mkdir(argv[3]);
|
||||
if (ret) {
|
||||
printf("** Unable to create a directory \"%s\" **\n", argv[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
2028
include/capitalization.h
Normal file
2028
include/capitalization.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -8,44 +8,188 @@
|
|||
#ifndef __CHARSET_H_
|
||||
#define __CHARSET_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define MAX_UTF8_PER_UTF16 3
|
||||
|
||||
/**
|
||||
* utf16_strlen() - Get the length of an utf16 string
|
||||
* console_read_unicode() - read Unicode code point from console
|
||||
*
|
||||
* Returns the number of 16 bit characters in an utf16 string, not
|
||||
* including the terminating NULL character.
|
||||
*
|
||||
* @in the string to measure
|
||||
* @return the string length
|
||||
* @code: pointer to store Unicode code point
|
||||
* Return: 0 = success
|
||||
*/
|
||||
size_t utf16_strlen(const uint16_t *in);
|
||||
int console_read_unicode(s32 *code);
|
||||
|
||||
/**
|
||||
* utf16_strnlen() - Get the length of a fixed-size utf16 string.
|
||||
* utf8_get() - get next UTF-8 code point from buffer
|
||||
*
|
||||
* Returns the number of 16 bit characters in an utf16 string,
|
||||
* not including the terminating NULL character, but at most
|
||||
* 'count' number of characters. In doing this, utf16_strnlen()
|
||||
* looks at only the first 'count' characters.
|
||||
*
|
||||
* @in the string to measure
|
||||
* @count the maximum number of characters to count
|
||||
* @return the string length, up to a maximum of 'count'
|
||||
* @src: pointer to current byte, updated to point to next byte
|
||||
* Return: code point, or 0 for end of string, or -1 if no legal
|
||||
* code point is found. In case of an error src points to
|
||||
* the incorrect byte.
|
||||
*/
|
||||
size_t utf16_strnlen(const uint16_t *in, size_t count);
|
||||
s32 utf8_get(const char **src);
|
||||
|
||||
/**
|
||||
* utf16_strcpy() - UTF16 equivalent of strcpy()
|
||||
* utf8_put() - write UTF-8 code point to buffer
|
||||
*
|
||||
* @code: code point
|
||||
* @dst: pointer to destination buffer, updated to next position
|
||||
* Return: -1 if the input parameters are invalid
|
||||
*/
|
||||
uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src);
|
||||
int utf8_put(s32 code, char **dst);
|
||||
|
||||
/**
|
||||
* utf16_strdup() - UTF16 equivalent of strdup()
|
||||
* utf8_utf16_strnlen() - length of a truncated utf-8 string after conversion
|
||||
* to utf-16
|
||||
*
|
||||
* @src: utf-8 string
|
||||
* @count: maximum number of code points to convert
|
||||
* Return: length in bytes after conversion to utf-16 without the
|
||||
* trailing \0. If an invalid UTF-8 sequence is hit one
|
||||
* word will be reserved for a replacement character.
|
||||
*/
|
||||
uint16_t *utf16_strdup(const uint16_t *s);
|
||||
size_t utf8_utf16_strnlen(const char *src, size_t count);
|
||||
|
||||
/**
|
||||
* utf8_utf16_strlen() - length of a utf-8 string after conversion to utf-16
|
||||
*
|
||||
* @src: utf-8 string
|
||||
* Return: length in bytes after conversion to utf-16 without the
|
||||
* trailing \0. -1 if the utf-8 string is not valid.
|
||||
*/
|
||||
#define utf8_utf16_strlen(a) utf8_utf16_strnlen((a), SIZE_MAX)
|
||||
|
||||
/**
|
||||
* utf8_utf16_strncpy() - copy utf-8 string to utf-16 string
|
||||
*
|
||||
* @dst: destination buffer
|
||||
* @src: source buffer
|
||||
* @count: maximum number of code points to copy
|
||||
* Return: -1 if the input parameters are invalid
|
||||
*/
|
||||
int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count);
|
||||
|
||||
/**
|
||||
* utf8_utf16_strcpy() - copy utf-8 string to utf-16 string
|
||||
*
|
||||
* @dst: destination buffer
|
||||
* @src: source buffer
|
||||
* Return: -1 if the input parameters are invalid
|
||||
*/
|
||||
#define utf8_utf16_strcpy(d, s) utf8_utf16_strncpy((d), (s), SIZE_MAX)
|
||||
|
||||
/**
|
||||
* utf16_get() - get next UTF-16 code point from buffer
|
||||
*
|
||||
* @src: pointer to current word, updated to point to next word
|
||||
* Return: code point, or 0 for end of string, or -1 if no legal
|
||||
* code point is found. In case of an error src points to
|
||||
* the incorrect word.
|
||||
*/
|
||||
s32 utf16_get(const u16 **src);
|
||||
|
||||
/**
|
||||
* utf16_put() - write UTF-16 code point to buffer
|
||||
*
|
||||
* @code: code point
|
||||
* @dst: pointer to destination buffer, updated to next position
|
||||
* Return: -1 if the input parameters are invalid
|
||||
*/
|
||||
int utf16_put(s32 code, u16 **dst);
|
||||
|
||||
/**
|
||||
* utf16_strnlen() - length of a truncated utf-16 string
|
||||
*
|
||||
* @src: utf-16 string
|
||||
* @count: maximum number of code points to convert
|
||||
* Return: length in code points. If an invalid UTF-16 sequence is
|
||||
* hit one position will be reserved for a replacement
|
||||
* character.
|
||||
*/
|
||||
size_t utf16_strnlen(const u16 *src, size_t count);
|
||||
|
||||
/**
|
||||
* utf16_utf8_strnlen() - length of a truncated utf-16 string after conversion
|
||||
* to utf-8
|
||||
*
|
||||
* @src: utf-16 string
|
||||
* @count: maximum number of code points to convert
|
||||
* Return: length in bytes after conversion to utf-8 without the
|
||||
* trailing \0. If an invalid UTF-16 sequence is hit one
|
||||
* byte will be reserved for a replacement character.
|
||||
*/
|
||||
size_t utf16_utf8_strnlen(const u16 *src, size_t count);
|
||||
|
||||
/**
|
||||
* utf16_utf8_strlen() - length of a utf-16 string after conversion to utf-8
|
||||
*
|
||||
* @src: utf-16 string
|
||||
* Return: length in bytes after conversion to utf-8 without the
|
||||
* trailing \0. -1 if the utf-16 string is not valid.
|
||||
*/
|
||||
#define utf16_utf8_strlen(a) utf16_utf8_strnlen((a), SIZE_MAX)
|
||||
|
||||
/**
|
||||
* utf16_utf8_strncpy() - copy utf-16 string to utf-8 string
|
||||
*
|
||||
* @dst: destination buffer
|
||||
* @src: source buffer
|
||||
* @count: maximum number of code points to copy
|
||||
* Return: -1 if the input parameters are invalid
|
||||
*/
|
||||
int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count);
|
||||
|
||||
/**
|
||||
* utf16_utf8_strcpy() - copy utf-16 string to utf-8 string
|
||||
*
|
||||
* @dst: destination buffer
|
||||
* @src: source buffer
|
||||
* Return: -1 if the input parameters are invalid
|
||||
*/
|
||||
#define utf16_utf8_strcpy(d, s) utf16_utf8_strncpy((d), (s), SIZE_MAX)
|
||||
|
||||
/**
|
||||
* utf_to_lower() - convert a Unicode letter to lower case
|
||||
*
|
||||
* @code: letter to convert
|
||||
* Return: lower case letter or unchanged letter
|
||||
*/
|
||||
s32 utf_to_lower(const s32 code);
|
||||
|
||||
/**
|
||||
* utf_to_upper() - convert a Unicode letter to upper case
|
||||
*
|
||||
* @code: letter to convert
|
||||
* Return: upper case letter or unchanged letter
|
||||
*/
|
||||
s32 utf_to_upper(const s32 code);
|
||||
|
||||
/**
|
||||
* u16_strlen - count non-zero words
|
||||
*
|
||||
* This function matches wsclen() if the -fshort-wchar compiler flag is set.
|
||||
* In the EFI context we explicitly need a function handling u16 strings.
|
||||
*
|
||||
* @in: null terminated u16 string
|
||||
* ReturnValue: number of non-zero words.
|
||||
* This is not the number of utf-16 letters!
|
||||
*/
|
||||
size_t u16_strlen(const u16 *in);
|
||||
|
||||
/**
|
||||
* u16_strlen - count non-zero words
|
||||
*
|
||||
* This function matches wscnlen_s() if the -fshort-wchar compiler flag is set.
|
||||
* In the EFI context we explicitly need a function handling u16 strings.
|
||||
*
|
||||
* @in: null terminated u16 string
|
||||
* @count: maximum number of words to count
|
||||
* ReturnValue: number of non-zero words.
|
||||
* This is not the number of utf-16 letters!
|
||||
*/
|
||||
size_t u16_strnlen(const u16 *in, size_t count);
|
||||
|
||||
/**
|
||||
* utf16_to_utf8() - Convert an utf16 string to utf8
|
||||
|
@ -63,17 +207,4 @@ uint16_t *utf16_strdup(const uint16_t *s);
|
|||
*/
|
||||
uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);
|
||||
|
||||
/**
|
||||
* utf8_to_utf16() - Convert an utf8 string to utf16
|
||||
*
|
||||
* Converts up to 'size' characters of the utf16 string 'src' to utf8
|
||||
* written to the 'dest' buffer. Stops at 0x00.
|
||||
*
|
||||
* @dest the destination buffer to write the utf8 characters
|
||||
* @src the source utf16 string
|
||||
* @size maximum number of utf16 characters to convert
|
||||
* @return the pointer to the first unwritten byte in 'dest'
|
||||
*/
|
||||
uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size);
|
||||
|
||||
#endif /* __CHARSET_H_ */
|
||||
|
|
|
@ -245,22 +245,26 @@
|
|||
#if defined(CONFIG_CMD_DHCP)
|
||||
#if defined(CONFIG_EFI_LOADER)
|
||||
/* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */
|
||||
#if defined(CONFIG_ARM64)
|
||||
#if defined(CONFIG_ARM64) || defined(__aarch64__)
|
||||
#define BOOTENV_EFI_PXE_ARCH "0xb"
|
||||
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00011:UNDI:003000"
|
||||
#elif defined(CONFIG_ARM)
|
||||
#elif defined(CONFIG_ARM) || defined(__arm__)
|
||||
#define BOOTENV_EFI_PXE_ARCH "0xa"
|
||||
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00010:UNDI:003000"
|
||||
#elif defined(CONFIG_X86)
|
||||
/* Always assume we're running 64bit */
|
||||
#elif defined(CONFIG_X86) || defined(__x86_64__)
|
||||
#define BOOTENV_EFI_PXE_ARCH "0x7"
|
||||
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00007:UNDI:003000"
|
||||
#elif defined(CONFIG_CPU_RISCV_32)
|
||||
#elif defined(__i386__)
|
||||
#define BOOTENV_EFI_PXE_ARCH "0x6"
|
||||
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00006:UNDI:003000"
|
||||
#elif defined(CONFIG_CPU_RISCV_32) || ((defined(__riscv) && __riscv_xlen == 32))
|
||||
#define BOOTENV_EFI_PXE_ARCH "0x19"
|
||||
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00025:UNDI:003000"
|
||||
#elif defined(CONFIG_CPU_RISCV_64)
|
||||
#elif defined(CONFIG_CPU_RISCV_64) || ((defined(__riscv) && __riscv_xlen == 64))
|
||||
#define BOOTENV_EFI_PXE_ARCH "0x1b"
|
||||
#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00027:UNDI:003000"
|
||||
#elif defined(CONFIG_SANDBOX)
|
||||
# error "sandbox EFI support is only supported on ARM and x86"
|
||||
#else
|
||||
#error Please specify an EFI client identifier
|
||||
#endif
|
||||
|
|
|
@ -20,9 +20,6 @@
|
|||
/* For timer, QEMU emulates an ARMv7/ARMv8 architected timer */
|
||||
#define CONFIG_SYS_HZ 1000
|
||||
|
||||
/* QEMU emulates the ARM AMBA PL031 RTC */
|
||||
#define CONFIG_SYS_RTC_PL031_BASE 0x09010000
|
||||
|
||||
/* Environment options */
|
||||
#define CONFIG_ENV_SIZE SZ_64K
|
||||
|
||||
|
|
40
include/cp1250.h
Normal file
40
include/cp1250.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
/*
|
||||
* Constant CP1250 contains the Unicode code points for characters 0x80 - 0xff
|
||||
* of the code page 1250.
|
||||
*/
|
||||
#define CP1250 { \
|
||||
0x20ac, 0x0000, 0x201a, 0x0000, \
|
||||
0x201e, 0x2026, 0x2020, 0x2021, \
|
||||
0x0000, 0x2030, 0x0160, 0x2039, \
|
||||
0x015a, 0x0164, 0x017d, 0x0179, \
|
||||
0x0000, 0x2018, 0x2019, 0x201c, \
|
||||
0x201d, 0x2022, 0x2013, 0x2014, \
|
||||
0x0000, 0x2122, 0x0161, 0x203a, \
|
||||
0x015b, 0x0165, 0x017e, 0x017a, \
|
||||
0x00a0, 0x02c7, 0x02d8, 0x0141, \
|
||||
0x00a4, 0x0104, 0x00a6, 0x00a7, \
|
||||
0x00a8, 0x00a9, 0x015e, 0x00ab, \
|
||||
0x00ac, 0x00ad, 0x00ae, 0x017b, \
|
||||
0x00b0, 0x00b1, 0x02db, 0x0142, \
|
||||
0x00b4, 0x00b5, 0x00b6, 0x00b7, \
|
||||
0x00b8, 0x0105, 0x015f, 0x00bb, \
|
||||
0x013d, 0x02dd, 0x013e, 0x017c, \
|
||||
0x0154, 0x00c1, 0x00c2, 0x0102, \
|
||||
0x00c4, 0x0139, 0x0106, 0x00c7, \
|
||||
0x010c, 0x00c9, 0x0118, 0x00cb, \
|
||||
0x011a, 0x00cd, 0x00ce, 0x010e, \
|
||||
0x0110, 0x0143, 0x0147, 0x00d3, \
|
||||
0x00d4, 0x0150, 0x00d6, 0x00d7, \
|
||||
0x0158, 0x016e, 0x00da, 0x0170, \
|
||||
0x00dc, 0x00dd, 0x0162, 0x00df, \
|
||||
0x0155, 0x00e1, 0x00e2, 0x0103, \
|
||||
0x00e4, 0x013a, 0x0107, 0x00e7, \
|
||||
0x010d, 0x00e9, 0x0119, 0x00eb, \
|
||||
0x011b, 0x00ed, 0x00ee, 0x010f, \
|
||||
0x0111, 0x0144, 0x0148, 0x00f3, \
|
||||
0x00f4, 0x0151, 0x00f6, 0x00f7, \
|
||||
0x0159, 0x016f, 0x00fa, 0x0171, \
|
||||
0x00fc, 0x00fd, 0x0163, 0x02d9, \
|
||||
}
|
40
include/cp437.h
Normal file
40
include/cp437.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
/*
|
||||
* Constant CP437 contains the Unicode code points for characters 0x80 - 0xff
|
||||
* of the code page 437.
|
||||
*/
|
||||
#define CP437 { \
|
||||
0x00c7, 0x00fc, 0x00e9, 0x00e2, \
|
||||
0x00e4, 0x00e0, 0x00e5, 0x00e7, \
|
||||
0x00ea, 0x00eb, 0x00e8, 0x00ef, \
|
||||
0x00ee, 0x00ec, 0x00c4, 0x00c5, \
|
||||
0x00c9, 0x00e6, 0x00c6, 0x00f4, \
|
||||
0x00f6, 0x00f2, 0x00fb, 0x00f9, \
|
||||
0x00ff, 0x00d6, 0x00dc, 0x00a2, \
|
||||
0x00a3, 0x00a5, 0x20a7, 0x0192, \
|
||||
0x00e1, 0x00ed, 0x00f3, 0x00fa, \
|
||||
0x00f1, 0x00d1, 0x00aa, 0x00ba, \
|
||||
0x00bf, 0x2310, 0x00ac, 0x00bd, \
|
||||
0x00bc, 0x00a1, 0x00ab, 0x00bb, \
|
||||
0x2591, 0x2592, 0x2593, 0x2502, \
|
||||
0x2524, 0x2561, 0x2562, 0x2556, \
|
||||
0x2555, 0x2563, 0x2551, 0x2557, \
|
||||
0x255d, 0x255c, 0x255b, 0x2510, \
|
||||
0x2514, 0x2534, 0x252c, 0x251c, \
|
||||
0x2500, 0x253c, 0x255e, 0x255f, \
|
||||
0x255a, 0x2554, 0x2569, 0x2566, \
|
||||
0x2560, 0x2550, 0x256c, 0x2567, \
|
||||
0x2568, 0x2564, 0x2565, 0x2559, \
|
||||
0x2558, 0x2552, 0x2553, 0x256b, \
|
||||
0x256a, 0x2518, 0x250c, 0x2588, \
|
||||
0x2584, 0x258c, 0x2590, 0x2580, \
|
||||
0x03b1, 0x00df, 0x0393, 0x03c0, \
|
||||
0x03a3, 0x03c3, 0x00b5, 0x03c4, \
|
||||
0x03a6, 0x0398, 0x03a9, 0x03b4, \
|
||||
0x221e, 0x03c6, 0x03b5, 0x2229, \
|
||||
0x2261, 0x00b1, 0x2265, 0x2264, \
|
||||
0x2320, 0x2321, 0x00f7, 0x2248, \
|
||||
0x00b0, 0x2219, 0x00b7, 0x221a, \
|
||||
0x207f, 0x00b2, 0x25a0, 0x00a0, \
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Extensible Firmware Interface
|
||||
* Based on 'Extensible Firmware Interface Specification' version 0.9,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Extensible Firmware Interface
|
||||
* Based on 'Extensible Firmware Interface Specification' version 0.9,
|
||||
|
@ -31,6 +32,7 @@ enum efi_timer_delay {
|
|||
EFI_TIMER_RELATIVE = 2
|
||||
};
|
||||
|
||||
#define efi_intn_t ssize_t
|
||||
#define efi_uintn_t size_t
|
||||
typedef uint16_t *efi_string_t;
|
||||
|
||||
|
@ -294,8 +296,7 @@ struct efi_runtime_services {
|
|||
EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \
|
||||
0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
|
||||
|
||||
struct efi_configuration_table
|
||||
{
|
||||
struct efi_configuration_table {
|
||||
efi_guid_t guid;
|
||||
void *table;
|
||||
};
|
||||
|
@ -307,7 +308,7 @@ struct efi_system_table {
|
|||
u16 *fw_vendor; /* physical addr of wchar_t vendor string */
|
||||
u32 fw_revision;
|
||||
efi_handle_t con_in_handle;
|
||||
struct efi_simple_input_interface *con_in;
|
||||
struct efi_simple_text_input_protocol *con_in;
|
||||
efi_handle_t con_out_handle;
|
||||
struct efi_simple_text_output_protocol *con_out;
|
||||
efi_handle_t stderr_handle;
|
||||
|
@ -338,19 +339,11 @@ struct efi_loaded_image {
|
|||
unsigned int image_code_type;
|
||||
unsigned int image_data_type;
|
||||
unsigned long unload;
|
||||
|
||||
/* Below are efi loader private fields */
|
||||
#ifdef CONFIG_EFI_LOADER
|
||||
void *reloc_base;
|
||||
aligned_u64 reloc_size;
|
||||
efi_status_t exit_status;
|
||||
struct jmp_buf_data exit_jmp;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define DEVICE_PATH_GUID \
|
||||
EFI_GUID(0x09576e91, 0x6d3f, 0x11d2, \
|
||||
0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
|
||||
0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
|
||||
|
||||
#define DEVICE_PATH_TYPE_END 0x7f
|
||||
# define DEVICE_PATH_SUB_TYPE_INSTANCE_END 0x01
|
||||
|
@ -475,8 +468,7 @@ struct efi_device_path_file_path {
|
|||
EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \
|
||||
0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
|
||||
|
||||
struct efi_block_io_media
|
||||
{
|
||||
struct efi_block_io_media {
|
||||
u32 media_id;
|
||||
char removable_media;
|
||||
char media_present;
|
||||
|
@ -521,7 +513,6 @@ struct simple_text_output_mode {
|
|||
bool cursor_visible;
|
||||
};
|
||||
|
||||
|
||||
#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
|
||||
EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \
|
||||
0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
|
||||
|
@ -588,20 +579,76 @@ struct efi_simple_text_output_protocol {
|
|||
struct simple_text_output_mode *mode;
|
||||
};
|
||||
|
||||
#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
|
||||
EFI_GUID(0xdd9e7534, 0x7762, 0x4698, \
|
||||
0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa)
|
||||
|
||||
struct efi_input_key {
|
||||
u16 scan_code;
|
||||
s16 unicode_char;
|
||||
};
|
||||
|
||||
#define EFI_SHIFT_STATE_INVALID 0x00000000
|
||||
#define EFI_RIGHT_SHIFT_PRESSED 0x00000001
|
||||
#define EFI_LEFT_SHIFT_PRESSED 0x00000002
|
||||
#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
|
||||
#define EFI_LEFT_CONTROL_PRESSED 0x00000008
|
||||
#define EFI_RIGHT_ALT_PRESSED 0x00000010
|
||||
#define EFI_LEFT_ALT_PRESSED 0x00000020
|
||||
#define EFI_RIGHT_LOGO_PRESSED 0x00000040
|
||||
#define EFI_LEFT_LOGO_PRESSED 0x00000080
|
||||
#define EFI_MENU_KEY_PRESSED 0x00000100
|
||||
#define EFI_SYS_REQ_PRESSED 0x00000200
|
||||
#define EFI_SHIFT_STATE_VALID 0x80000000
|
||||
|
||||
#define EFI_TOGGLE_STATE_INVALID 0x00
|
||||
#define EFI_SCROLL_LOCK_ACTIVE 0x01
|
||||
#define EFI_NUM_LOCK_ACTIVE 0x02
|
||||
#define EFI_CAPS_LOCK_ACTIVE 0x04
|
||||
#define EFI_KEY_STATE_EXPOSED 0x40
|
||||
#define EFI_TOGGLE_STATE_VALID 0x80
|
||||
|
||||
struct efi_key_state {
|
||||
u32 key_shift_state;
|
||||
u8 key_toggle_state;
|
||||
};
|
||||
|
||||
struct efi_key_data {
|
||||
struct efi_input_key key;
|
||||
struct efi_key_state key_state;
|
||||
};
|
||||
|
||||
struct efi_simple_text_input_ex_protocol {
|
||||
efi_status_t (EFIAPI *reset) (
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
bool extended_verification);
|
||||
efi_status_t (EFIAPI *read_key_stroke_ex) (
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
struct efi_key_data *key_data);
|
||||
struct efi_event *wait_for_key_ex;
|
||||
efi_status_t (EFIAPI *set_state) (
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
u8 key_toggle_state);
|
||||
efi_status_t (EFIAPI *register_key_notify) (
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
struct efi_key_data *key_data,
|
||||
efi_status_t (EFIAPI *key_notify_function)(
|
||||
struct efi_key_data *key_data),
|
||||
void **notify_handle);
|
||||
efi_status_t (EFIAPI *unregister_key_notify) (
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
void *notification_handle);
|
||||
};
|
||||
|
||||
#define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
|
||||
EFI_GUID(0x387477c1, 0x69c7, 0x11d2, \
|
||||
0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
|
||||
|
||||
struct efi_simple_input_interface {
|
||||
efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this,
|
||||
bool ExtendedVerification);
|
||||
struct efi_simple_text_input_protocol {
|
||||
efi_status_t(EFIAPI *reset)(struct efi_simple_text_input_protocol *this,
|
||||
bool extended_verification);
|
||||
efi_status_t(EFIAPI *read_key_stroke)(
|
||||
struct efi_simple_input_interface *this,
|
||||
struct efi_simple_text_input_protocol *this,
|
||||
struct efi_input_key *key);
|
||||
struct efi_event *wait_for_key;
|
||||
};
|
||||
|
@ -610,8 +657,7 @@ struct efi_simple_input_interface {
|
|||
EFI_GUID(0x8b843e20, 0x8132, 0x4852, \
|
||||
0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c)
|
||||
|
||||
struct efi_device_path_to_text_protocol
|
||||
{
|
||||
struct efi_device_path_to_text_protocol {
|
||||
uint16_t *(EFIAPI *convert_device_node_to_text)(
|
||||
struct efi_device_path *device_node,
|
||||
bool display_only,
|
||||
|
@ -659,8 +705,7 @@ struct efi_device_path_utilities_protocol {
|
|||
#define EFI_GOT_BGRA8 1
|
||||
#define EFI_GOT_BITMASK 2
|
||||
|
||||
struct efi_gop_mode_info
|
||||
{
|
||||
struct efi_gop_mode_info {
|
||||
u32 version;
|
||||
u32 width;
|
||||
u32 height;
|
||||
|
@ -669,8 +714,7 @@ struct efi_gop_mode_info
|
|||
u32 pixels_per_scanline;
|
||||
};
|
||||
|
||||
struct efi_gop_mode
|
||||
{
|
||||
struct efi_gop_mode {
|
||||
u32 max_mode;
|
||||
u32 mode;
|
||||
struct efi_gop_mode_info *info;
|
||||
|
@ -691,8 +735,7 @@ struct efi_gop_pixel {
|
|||
#define EFI_BLT_BUFFER_TO_VIDEO 2
|
||||
#define EFI_BLT_VIDEO_TO_VIDEO 3
|
||||
|
||||
struct efi_gop
|
||||
{
|
||||
struct efi_gop {
|
||||
efi_status_t (EFIAPI *query_mode)(struct efi_gop *this, u32 mode_number,
|
||||
efi_uintn_t *size_of_info,
|
||||
struct efi_gop_mode_info **info);
|
||||
|
@ -762,8 +805,7 @@ struct efi_simple_network_mode {
|
|||
/* revision of the simple network protocol */
|
||||
#define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION 0x00010000
|
||||
|
||||
struct efi_simple_network
|
||||
{
|
||||
struct efi_simple_network {
|
||||
u64 revision;
|
||||
efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
|
||||
efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
|
||||
|
@ -808,8 +850,7 @@ struct efi_pxe_packet {
|
|||
u8 packet[1472];
|
||||
};
|
||||
|
||||
struct efi_pxe_mode
|
||||
{
|
||||
struct efi_pxe_mode {
|
||||
u8 started;
|
||||
u8 ipv6_available;
|
||||
u8 ipv6_supported;
|
||||
|
@ -958,4 +999,24 @@ struct efi_driver_binding_protocol {
|
|||
efi_handle_t driver_binding_handle;
|
||||
};
|
||||
|
||||
#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
|
||||
EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
|
||||
0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
|
||||
struct efi_unicode_collation_protocol {
|
||||
efi_intn_t (EFIAPI *stri_coll)(
|
||||
struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2);
|
||||
bool (EFIAPI *metai_match)(struct efi_unicode_collation_protocol *this,
|
||||
const u16 *string, const u16 *patter);
|
||||
void (EFIAPI *str_lwr)(struct efi_unicode_collation_protocol
|
||||
*this, u16 *string);
|
||||
void (EFIAPI *str_upr)(struct efi_unicode_collation_protocol *this,
|
||||
u16 *string);
|
||||
void (EFIAPI *fat_to_str)(struct efi_unicode_collation_protocol *this,
|
||||
efi_uintn_t fat_size, char *fat, u16 *string);
|
||||
bool (EFIAPI *str_to_fat)(struct efi_unicode_collation_protocol *this,
|
||||
const u16 *string, efi_uintn_t fat_size,
|
||||
char *fat);
|
||||
char *supported_languages;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,13 +13,18 @@
|
|||
#include <efi_api.h>
|
||||
|
||||
/* No need for efi loader support in SPL */
|
||||
#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER)
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
/* Maximum number of configuration tables */
|
||||
#define EFI_MAX_CONFIGURATION_TABLES 16
|
||||
|
||||
/* GUID used by the root node */
|
||||
#define U_BOOT_GUID \
|
||||
EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
|
||||
0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
|
||||
|
||||
int __efi_entry_check(void);
|
||||
int __efi_exit_check(void);
|
||||
const char *__efi_nesting(void);
|
||||
|
@ -92,15 +97,20 @@ extern struct efi_runtime_services efi_runtime_services;
|
|||
extern struct efi_system_table systab;
|
||||
|
||||
extern struct efi_simple_text_output_protocol efi_con_out;
|
||||
extern struct efi_simple_input_interface efi_con_in;
|
||||
extern struct efi_simple_text_input_protocol efi_con_in;
|
||||
extern struct efi_console_control_protocol efi_console_control;
|
||||
extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
|
||||
/* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */
|
||||
extern const struct efi_device_path_utilities_protocol
|
||||
efi_device_path_utilities;
|
||||
/* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */
|
||||
extern const struct efi_unicode_collation_protocol
|
||||
efi_unicode_collation_protocol;
|
||||
|
||||
uint16_t *efi_dp_str(struct efi_device_path *dp);
|
||||
|
||||
/* GUID of the U-Boot root node */
|
||||
extern const efi_guid_t efi_u_boot_guid;
|
||||
/* GUID of the EFI_BLOCK_IO_PROTOCOL */
|
||||
extern const efi_guid_t efi_block_io_guid;
|
||||
extern const efi_guid_t efi_global_variable_guid;
|
||||
|
@ -127,6 +137,8 @@ extern const efi_guid_t efi_file_info_guid;
|
|||
/* GUID for file system information */
|
||||
extern const efi_guid_t efi_file_system_info_guid;
|
||||
extern const efi_guid_t efi_guid_device_path_utilities_protocol;
|
||||
/* GUID of the Unicode collation protocol */
|
||||
extern const efi_guid_t efi_guid_unicode_collation_protocol;
|
||||
|
||||
extern unsigned int __efi_runtime_start, __efi_runtime_stop;
|
||||
extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
|
||||
|
@ -171,6 +183,20 @@ struct efi_object {
|
|||
void *handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efi_loaded_image_obj - handle of a loaded image
|
||||
*/
|
||||
struct efi_loaded_image_obj {
|
||||
/* Generic EFI object parent class data */
|
||||
struct efi_object parent;
|
||||
void *reloc_base;
|
||||
aligned_u64 reloc_size;
|
||||
efi_status_t exit_status;
|
||||
struct jmp_buf_data exit_jmp;
|
||||
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
|
||||
struct efi_system_table *st);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efi_event
|
||||
*
|
||||
|
@ -205,6 +231,8 @@ extern struct list_head efi_obj_list;
|
|||
/* List of all events */
|
||||
extern struct list_head efi_events;
|
||||
|
||||
/* Called by bootefi to initialize root node */
|
||||
efi_status_t efi_root_node_register(void);
|
||||
/* Called by bootefi to initialize runtime */
|
||||
efi_status_t efi_initialize_system_table(void);
|
||||
/* Called by bootefi to make console interface available */
|
||||
|
@ -250,7 +278,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
|
|||
/* Called from places to check whether a timer expired */
|
||||
void efi_timer_check(void);
|
||||
/* PE loader implementation */
|
||||
void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
|
||||
void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
|
||||
struct efi_loaded_image *loaded_image_info);
|
||||
/* Called once to store the pristine gd pointer */
|
||||
void efi_save_gd(void);
|
||||
/* Special case handler for error/abort that just tries to dtrt to get
|
||||
|
@ -331,14 +360,12 @@ int efi_memory_init(void);
|
|||
/* Adds new or overrides configuration table entry to the system table */
|
||||
efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table);
|
||||
/* Sets up a loaded image */
|
||||
efi_status_t efi_setup_loaded_image(
|
||||
struct efi_loaded_image *info, struct efi_object *obj,
|
||||
struct efi_device_path *device_path,
|
||||
struct efi_device_path *file_path);
|
||||
efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
|
||||
struct efi_device_path *file_path,
|
||||
struct efi_loaded_image_obj **handle_ptr,
|
||||
struct efi_loaded_image **info_ptr);
|
||||
efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
|
||||
void **buffer);
|
||||
/* Print information about a loaded image */
|
||||
efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc);
|
||||
/* Print information about all loaded images */
|
||||
void efi_print_image_infos(void *pc);
|
||||
|
||||
|
@ -397,7 +424,15 @@ efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
|
|||
(((_dp)->type == DEVICE_PATH_TYPE_##_type) && \
|
||||
((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype))
|
||||
|
||||
/* Convert strings from normal C strings to uEFI strings */
|
||||
/**
|
||||
* ascii2unicode() - convert ASCII string to UTF-16 string
|
||||
*
|
||||
* A zero terminated ASCII string is converted to a zero terminated UTF-16
|
||||
* string. The output buffer must be preassigned.
|
||||
*
|
||||
* @unicode: preassigned output buffer for UTF-16 string
|
||||
* @ascii: ASCII string to be converted
|
||||
*/
|
||||
static inline void ascii2unicode(u16 *unicode, const char *ascii)
|
||||
{
|
||||
while (*ascii)
|
||||
|
@ -460,7 +495,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
|
|||
void *efi_bootmgr_load(struct efi_device_path **device_path,
|
||||
struct efi_device_path **file_path);
|
||||
|
||||
#else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
|
||||
#else /* CONFIG_IS_ENABLED(EFI_LOADER) */
|
||||
|
||||
/* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
|
||||
#define __efi_runtime_data
|
||||
|
@ -477,6 +512,6 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
|
|||
static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
|
||||
static inline void efi_print_image_infos(void *pc) { }
|
||||
|
||||
#endif /* CONFIG_EFI_LOADER && !CONFIG_SPL_BUILD */
|
||||
#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
|
||||
|
||||
#endif /* _EFI_LOADER_H */
|
||||
|
|
|
@ -53,7 +53,7 @@ enum efi_test_phase {
|
|||
};
|
||||
|
||||
extern struct efi_simple_text_output_protocol *con_out;
|
||||
extern struct efi_simple_input_interface *con_in;
|
||||
extern struct efi_simple_text_input_protocol *con_in;
|
||||
|
||||
/*
|
||||
* Exit the boot services.
|
||||
|
@ -76,6 +76,22 @@ void efi_st_exit_boot_services(void);
|
|||
void efi_st_printc(int color, const char *fmt, ...)
|
||||
__attribute__ ((format (__printf__, 2, 3)));
|
||||
|
||||
/**
|
||||
* efi_st_translate_char() - translate a unicode character to a string
|
||||
*
|
||||
* @code: unicode character
|
||||
* Return: string
|
||||
*/
|
||||
u16 *efi_st_translate_char(u16 code);
|
||||
|
||||
/**
|
||||
* efi_st_translate_code() - translate a scan code to a human readable string
|
||||
*
|
||||
* @code: unicode character
|
||||
* Return: string
|
||||
*/
|
||||
u16 *efi_st_translate_code(u16 code);
|
||||
|
||||
/*
|
||||
* Compare memory.
|
||||
* We cannot use lib/string.c due to different CFLAGS values.
|
||||
|
|
|
@ -173,6 +173,8 @@ typedef struct {
|
|||
int fatbufnum; /* Used by get_fatent, init to -1 */
|
||||
int rootdir_size; /* Size of root dir for non-FAT32 */
|
||||
__u32 root_cluster; /* First cluster of root dir for FAT32 */
|
||||
u32 total_sect; /* Number of sectors */
|
||||
int fats; /* Number of FATs */
|
||||
} fsdata;
|
||||
|
||||
static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)
|
||||
|
@ -201,5 +203,7 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
|
|||
int fat_opendir(const char *filename, struct fs_dir_stream **dirsp);
|
||||
int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
|
||||
void fat_closedir(struct fs_dir_stream *dirs);
|
||||
int fat_unlink(const char *filename);
|
||||
int fat_mkdir(const char *dirname);
|
||||
void fat_close(void);
|
||||
#endif /* _FAT_H_ */
|
||||
|
|
22
include/fs.h
22
include/fs.h
|
@ -155,6 +155,24 @@ struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs);
|
|||
*/
|
||||
void fs_closedir(struct fs_dir_stream *dirs);
|
||||
|
||||
/*
|
||||
* fs_unlink - delete a file or directory
|
||||
*
|
||||
* If a given name is a directory, it will be deleted only if it's empty
|
||||
*
|
||||
* @filename: Name of file or directory to delete
|
||||
* @return 0 on success, -1 on error conditions
|
||||
*/
|
||||
int fs_unlink(const char *filename);
|
||||
|
||||
/*
|
||||
* fs_mkdir - Create a directory
|
||||
*
|
||||
* @filename: Name of directory to create
|
||||
* @return 0 on success, -1 on error conditions
|
||||
*/
|
||||
int fs_mkdir(const char *filename);
|
||||
|
||||
/*
|
||||
* Common implementation for various filesystem commands, optionally limited
|
||||
* to a specific filesystem type via the fstype parameter.
|
||||
|
@ -169,6 +187,10 @@ int file_exists(const char *dev_type, const char *dev_part, const char *file,
|
|||
int fstype);
|
||||
int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
||||
int fstype);
|
||||
int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
||||
int fstype);
|
||||
int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
|
||||
int fstype);
|
||||
|
||||
/*
|
||||
* Determine the UUID of the specified filesystem and print it. Optionally it is
|
||||
|
|
21
include/os.h
21
include/os.h
|
@ -331,24 +331,7 @@ int os_spl_to_uboot(const char *fname);
|
|||
void os_localtime(struct rtc_time *rt);
|
||||
|
||||
/**
|
||||
* os_setjmp() - Call setjmp()
|
||||
*
|
||||
* Call the host system's setjmp() function.
|
||||
*
|
||||
* @jmp: Buffer to store current execution state
|
||||
* @size: Size of buffer
|
||||
* @return normal setjmp() value if OK, -ENOSPC if @size is too small
|
||||
* os_abort() - Raise SIGABRT to exit sandbox (e.g. to debugger)
|
||||
*/
|
||||
int os_setjmp(ulong *jmp, int size);
|
||||
|
||||
/**
|
||||
* os_longjmp() - Call longjmp()
|
||||
*
|
||||
* Call the host system's longjmp() function.
|
||||
*
|
||||
* @jmp: Buffer where previous execution state was stored
|
||||
* @ret: Value to pass to longjmp()
|
||||
*/
|
||||
void os_longjmp(ulong *jmp, int ret);
|
||||
|
||||
void os_abort(void);
|
||||
#endif
|
||||
|
|
|
@ -23,10 +23,11 @@ struct unit_test;
|
|||
int cmd_ut_category(const char *name, struct unit_test *tests, int n_ents,
|
||||
int argc, char * const argv[]);
|
||||
|
||||
int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
|
||||
int do_ut_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
int do_ut_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
|
||||
int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
|
||||
|
||||
#endif /* __TEST_SUITES_H__ */
|
||||
|
|
|
@ -19,7 +19,12 @@ obj-$(CONFIG_ARCH_AT91) += at91/
|
|||
obj-$(CONFIG_OPTEE) += optee/
|
||||
|
||||
obj-$(CONFIG_AES) += aes.o
|
||||
|
||||
ifndef API_BUILD
|
||||
ifneq ($(CONFIG_UT_UNICODE)$(CONFIG_EFI_LOADER),)
|
||||
obj-y += charset.o
|
||||
endif
|
||||
endif
|
||||
obj-$(CONFIG_USB_TTY) += circbuf.o
|
||||
obj-y += crc7.o
|
||||
obj-y += crc8.o
|
||||
|
|
403
lib/charset.c
403
lib/charset.c
|
@ -5,46 +5,345 @@
|
|||
* Copyright (c) 2017 Rob Clark
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <charset.h>
|
||||
#include <capitalization.h>
|
||||
#include <malloc.h>
|
||||
|
||||
/*
|
||||
* utf8/utf16 conversion mostly lifted from grub
|
||||
*/
|
||||
static struct capitalization_table capitalization_table[] =
|
||||
#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
|
||||
UNICODE_CAPITALIZATION_TABLE;
|
||||
#elif CONFIG_FAT_DEFAULT_CODEPAGE == 1250
|
||||
CP1250_CAPITALIZATION_TABLE;
|
||||
#else
|
||||
CP437_CAPITALIZATION_TABLE;
|
||||
#endif
|
||||
|
||||
size_t utf16_strlen(const uint16_t *in)
|
||||
/**
|
||||
* get_code() - read Unicode code point from UTF-8 stream
|
||||
*
|
||||
* @read_u8: - stream reader
|
||||
* @src: - string buffer passed to stream reader, optional
|
||||
* Return: - Unicode code point
|
||||
*/
|
||||
static int get_code(u8 (*read_u8)(void *data), void *data)
|
||||
{
|
||||
s32 ch = 0;
|
||||
|
||||
ch = read_u8(data);
|
||||
if (!ch)
|
||||
return 0;
|
||||
if (ch >= 0xc2 && ch <= 0xf4) {
|
||||
int code = 0;
|
||||
|
||||
if (ch >= 0xe0) {
|
||||
if (ch >= 0xf0) {
|
||||
/* 0xf0 - 0xf4 */
|
||||
ch &= 0x07;
|
||||
code = ch << 18;
|
||||
ch = read_u8(data);
|
||||
if (ch < 0x80 || ch > 0xbf)
|
||||
goto error;
|
||||
ch &= 0x3f;
|
||||
} else {
|
||||
/* 0xe0 - 0xef */
|
||||
ch &= 0x0f;
|
||||
}
|
||||
code += ch << 12;
|
||||
if ((code >= 0xD800 && code <= 0xDFFF) ||
|
||||
code >= 0x110000)
|
||||
goto error;
|
||||
ch = read_u8(data);
|
||||
if (ch < 0x80 || ch > 0xbf)
|
||||
goto error;
|
||||
}
|
||||
/* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
|
||||
ch &= 0x3f;
|
||||
code += ch << 6;
|
||||
ch = read_u8(data);
|
||||
if (ch < 0x80 || ch > 0xbf)
|
||||
goto error;
|
||||
ch &= 0x3f;
|
||||
ch += code;
|
||||
} else if (ch >= 0x80) {
|
||||
goto error;
|
||||
}
|
||||
return ch;
|
||||
error:
|
||||
return '?';
|
||||
}
|
||||
|
||||
/**
|
||||
* read_string() - read byte from character string
|
||||
*
|
||||
* @data: - pointer to string
|
||||
* Return: - byte read
|
||||
*
|
||||
* The string pointer is incremented if it does not point to '\0'.
|
||||
*/
|
||||
static u8 read_string(void *data)
|
||||
|
||||
{
|
||||
const char **src = (const char **)data;
|
||||
u8 c;
|
||||
|
||||
if (!src || !*src || !**src)
|
||||
return 0;
|
||||
c = **src;
|
||||
++*src;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_console() - read byte from console
|
||||
*
|
||||
* @src - not used, needed to match interface
|
||||
* Return: - byte read
|
||||
*/
|
||||
static u8 read_console(void *data)
|
||||
{
|
||||
return getc();
|
||||
}
|
||||
|
||||
int console_read_unicode(s32 *code)
|
||||
{
|
||||
if (!tstc()) {
|
||||
/* No input available */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Read Unicode code */
|
||||
*code = get_code(read_console, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 utf8_get(const char **src)
|
||||
{
|
||||
return get_code(read_string, src);
|
||||
}
|
||||
|
||||
int utf8_put(s32 code, char **dst)
|
||||
{
|
||||
if (!dst || !*dst)
|
||||
return -1;
|
||||
if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
|
||||
return -1;
|
||||
if (code <= 0x007F) {
|
||||
**dst = code;
|
||||
} else {
|
||||
if (code <= 0x07FF) {
|
||||
**dst = code >> 6 | 0xC0;
|
||||
} else {
|
||||
if (code < 0x10000) {
|
||||
**dst = code >> 12 | 0xE0;
|
||||
} else {
|
||||
**dst = code >> 18 | 0xF0;
|
||||
++*dst;
|
||||
**dst = (code >> 12 & 0x3F) | 0x80;
|
||||
}
|
||||
++*dst;
|
||||
**dst = (code >> 6 & 0x3F) | 0x80;
|
||||
}
|
||||
++*dst;
|
||||
**dst = (code & 0x3F) | 0x80;
|
||||
}
|
||||
++*dst;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t utf8_utf16_strnlen(const char *src, size_t count)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
for (; *src && count; --count) {
|
||||
s32 code = utf8_get(&src);
|
||||
|
||||
if (!code)
|
||||
break;
|
||||
if (code < 0) {
|
||||
/* Reserve space for a replacement character */
|
||||
len += 1;
|
||||
} else if (code < 0x10000) {
|
||||
len += 1;
|
||||
} else {
|
||||
len += 2;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count)
|
||||
{
|
||||
if (!src || !dst || !*dst)
|
||||
return -1;
|
||||
|
||||
for (; count && *src; --count) {
|
||||
s32 code = utf8_get(&src);
|
||||
|
||||
if (code < 0)
|
||||
code = '?';
|
||||
utf16_put(code, dst);
|
||||
}
|
||||
**dst = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 utf16_get(const u16 **src)
|
||||
{
|
||||
s32 code, code2;
|
||||
|
||||
if (!src || !*src)
|
||||
return -1;
|
||||
if (!**src)
|
||||
return 0;
|
||||
code = **src;
|
||||
++*src;
|
||||
if (code >= 0xDC00 && code <= 0xDFFF)
|
||||
return -1;
|
||||
if (code >= 0xD800 && code <= 0xDBFF) {
|
||||
if (!**src)
|
||||
return -1;
|
||||
code &= 0x3ff;
|
||||
code <<= 10;
|
||||
code += 0x10000;
|
||||
code2 = **src;
|
||||
++*src;
|
||||
if (code2 <= 0xDC00 || code2 >= 0xDFFF)
|
||||
return -1;
|
||||
code2 &= 0x3ff;
|
||||
code += code2;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
int utf16_put(s32 code, u16 **dst)
|
||||
{
|
||||
if (!dst || !*dst)
|
||||
return -1;
|
||||
if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
|
||||
return -1;
|
||||
if (code < 0x10000) {
|
||||
**dst = code;
|
||||
} else {
|
||||
code -= 0x10000;
|
||||
**dst = code >> 10 | 0xD800;
|
||||
++*dst;
|
||||
**dst = (code & 0x3ff) | 0xDC00;
|
||||
}
|
||||
++*dst;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t utf16_strnlen(const u16 *src, size_t count)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
for (; *src && count; --count) {
|
||||
s32 code = utf16_get(&src);
|
||||
|
||||
if (!code)
|
||||
break;
|
||||
/*
|
||||
* In case of an illegal sequence still reserve space for a
|
||||
* replacement character.
|
||||
*/
|
||||
++len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t utf16_utf8_strnlen(const u16 *src, size_t count)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
for (; *src && count; --count) {
|
||||
s32 code = utf16_get(&src);
|
||||
|
||||
if (!code)
|
||||
break;
|
||||
if (code < 0)
|
||||
/* Reserve space for a replacement character */
|
||||
len += 1;
|
||||
else if (code < 0x80)
|
||||
len += 1;
|
||||
else if (code < 0x800)
|
||||
len += 2;
|
||||
else if (code < 0x10000)
|
||||
len += 3;
|
||||
else
|
||||
len += 4;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count)
|
||||
{
|
||||
if (!src || !dst || !*dst)
|
||||
return -1;
|
||||
|
||||
for (; count && *src; --count) {
|
||||
s32 code = utf16_get(&src);
|
||||
|
||||
if (code < 0)
|
||||
code = '?';
|
||||
utf8_put(code, dst);
|
||||
}
|
||||
**dst = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 utf_to_lower(const s32 code)
|
||||
{
|
||||
struct capitalization_table *pos = capitalization_table;
|
||||
s32 ret = code;
|
||||
|
||||
if (code <= 0x7f) {
|
||||
if (code >= 'A' && code <= 'Z')
|
||||
ret += 0x20;
|
||||
return ret;
|
||||
}
|
||||
for (; pos->upper; ++pos) {
|
||||
if (pos->upper == code) {
|
||||
ret = pos->lower;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 utf_to_upper(const s32 code)
|
||||
{
|
||||
struct capitalization_table *pos = capitalization_table;
|
||||
s32 ret = code;
|
||||
|
||||
if (code <= 0x7f) {
|
||||
if (code >= 'a' && code <= 'z')
|
||||
ret -= 0x20;
|
||||
return ret;
|
||||
}
|
||||
for (; pos->lower; ++pos) {
|
||||
if (pos->lower == code) {
|
||||
ret = pos->upper;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t u16_strlen(const u16 *in)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; in[i]; i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t utf16_strnlen(const uint16_t *in, size_t count)
|
||||
size_t u16_strnlen(const u16 *in, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; count-- && in[i]; i++);
|
||||
return i;
|
||||
}
|
||||
|
||||
uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src)
|
||||
{
|
||||
uint16_t *tmp = dest;
|
||||
|
||||
while ((*dest++ = *src++) != '\0')
|
||||
/* nothing */;
|
||||
return tmp;
|
||||
|
||||
}
|
||||
|
||||
uint16_t *utf16_strdup(const uint16_t *s)
|
||||
{
|
||||
uint16_t *new;
|
||||
if (!s || !(new = malloc((utf16_strlen(s) + 1) * 2)))
|
||||
return NULL;
|
||||
utf16_strcpy(new, s);
|
||||
return new;
|
||||
}
|
||||
|
||||
/* Convert UTF-16 to UTF-8. */
|
||||
uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
|
||||
{
|
||||
|
@ -97,59 +396,3 @@ uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
|
|||
|
||||
return dest;
|
||||
}
|
||||
|
||||
uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size)
|
||||
{
|
||||
while (size--) {
|
||||
int extension_bytes;
|
||||
uint32_t code;
|
||||
|
||||
extension_bytes = 0;
|
||||
if (*src <= 0x7f) {
|
||||
code = *src++;
|
||||
/* Exit on zero byte */
|
||||
if (!code)
|
||||
size = 0;
|
||||
} else if (*src <= 0xbf) {
|
||||
/* Illegal code */
|
||||
code = '?';
|
||||
} else if (*src <= 0xdf) {
|
||||
code = *src++ & 0x1f;
|
||||
extension_bytes = 1;
|
||||
} else if (*src <= 0xef) {
|
||||
code = *src++ & 0x0f;
|
||||
extension_bytes = 2;
|
||||
} else if (*src <= 0xf7) {
|
||||
code = *src++ & 0x07;
|
||||
extension_bytes = 3;
|
||||
} else {
|
||||
/* Illegal code */
|
||||
code = '?';
|
||||
}
|
||||
|
||||
for (; extension_bytes && size; --size, --extension_bytes) {
|
||||
if ((*src & 0xc0) == 0x80) {
|
||||
code <<= 6;
|
||||
code |= *src++ & 0x3f;
|
||||
} else {
|
||||
/* Illegal code */
|
||||
code = '?';
|
||||
++src;
|
||||
--size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (code < 0x10000) {
|
||||
*dest++ = code;
|
||||
} else {
|
||||
/*
|
||||
* Simplified expression for
|
||||
* (((code - 0x10000) >> 10) & 0x3ff) | 0xd800
|
||||
*/
|
||||
*dest++ = (code >> 10) + 0xd7c0;
|
||||
*dest++ = (code & 0x3ff) | 0xdc00;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
|
||||
#include <efi_driver.h>
|
||||
|
||||
/*
|
||||
* Check node type. We do not support partitions as controller handles.
|
||||
/**
|
||||
* check_node_type() - check node type
|
||||
*
|
||||
* @handle handle to be checked
|
||||
* @return status code
|
||||
* We do not support partitions as controller handles.
|
||||
*
|
||||
* @handle: handle to be checked
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t check_node_type(efi_handle_t handle)
|
||||
{
|
||||
|
@ -44,13 +46,13 @@ static efi_status_t check_node_type(efi_handle_t handle)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the driver supports the controller.
|
||||
/**
|
||||
* efi_uc_supported() - check if the driver supports the controller
|
||||
*
|
||||
* @this driver binding protocol
|
||||
* @controller_handle handle of the controller
|
||||
* @remaining_device_path path specifying the child controller
|
||||
* @return status code
|
||||
* @this: driver binding protocol
|
||||
* @controller_handle: handle of the controller
|
||||
* @remaining_device_path: path specifying the child controller
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_uc_supported(
|
||||
struct efi_driver_binding_protocol *this,
|
||||
|
@ -92,13 +94,13 @@ out:
|
|||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create child controllers and attach driver.
|
||||
/**
|
||||
* efi_uc_start() - create child controllers and attach driver
|
||||
*
|
||||
* @this driver binding protocol
|
||||
* @controller_handle handle of the controller
|
||||
* @remaining_device_path path specifying the child controller
|
||||
* @return status code
|
||||
* @this: driver binding protocol
|
||||
* @controller_handle: handle of the controller
|
||||
* @remaining_device_path: path specifying the child controller
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_uc_start(
|
||||
struct efi_driver_binding_protocol *this,
|
||||
|
@ -146,12 +148,13 @@ out:
|
|||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a single child controller from the parent controller.
|
||||
/**
|
||||
* disconnect_child() - remove a single child controller from the parent
|
||||
* controller
|
||||
*
|
||||
* @controller_handle parent controller
|
||||
* @child_handle child controller
|
||||
* @return status code
|
||||
* @controller_handle: parent controller
|
||||
* @child_handle: child controller
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t disconnect_child(efi_handle_t controller_handle,
|
||||
efi_handle_t child_handle)
|
||||
|
@ -176,14 +179,14 @@ static efi_status_t disconnect_child(efi_handle_t controller_handle,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove child controllers and disconnect the controller.
|
||||
/**
|
||||
* efi_uc_stop() - Remove child controllers and disconnect the controller
|
||||
*
|
||||
* @this driver binding protocol
|
||||
* @controller_handle handle of the controller
|
||||
* @number_of_children number of child controllers to remove
|
||||
* @child_handle_buffer handles of the child controllers to remove
|
||||
* @return status code
|
||||
* @this: driver binding protocol
|
||||
* @controller_handle: handle of the controller
|
||||
* @number_of_children: number of child controllers to remove
|
||||
* @child_handle_buffer: handles of the child controllers to remove
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_uc_stop(
|
||||
struct efi_driver_binding_protocol *this,
|
||||
|
@ -241,6 +244,12 @@ out:
|
|||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_add_driver() - add driver
|
||||
*
|
||||
* @drv: driver to add
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t efi_add_driver(struct driver *drv)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
@ -280,11 +289,12 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the EFI drivers.
|
||||
* Called by board_init_r().
|
||||
/**
|
||||
* efi_driver_init() - initialize the EFI drivers
|
||||
*
|
||||
* @return 0 = success, any other value will stop further execution
|
||||
* Called by efi_init_obj_list().
|
||||
*
|
||||
* Return: 0 = success, any other value will stop further execution
|
||||
*/
|
||||
efi_status_t efi_driver_init(void)
|
||||
{
|
||||
|
@ -309,12 +319,24 @@ efi_status_t efi_driver_init(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_uc_init() - initialize the EFI uclass
|
||||
*
|
||||
* @class: the EFI uclass
|
||||
* Return: 0 = success
|
||||
*/
|
||||
static int efi_uc_init(struct uclass *class)
|
||||
{
|
||||
printf("EFI: Initializing UCLASS_EFI\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_uc_destroy() - destroy the EFI uclass
|
||||
*
|
||||
* @class: the EFI uclass
|
||||
* Return: 0 = success
|
||||
*/
|
||||
static int efi_uc_destroy(struct uclass *class)
|
||||
{
|
||||
printf("Destroying UCLASS_EFI\n");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config EFI_LOADER
|
||||
bool "Support running EFI Applications in U-Boot"
|
||||
depends on (ARM || X86 || RISCV) && OF_LIBFDT
|
||||
depends on (ARM || X86 || RISCV || SANDBOX) && OF_LIBFDT
|
||||
# We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB
|
||||
depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT
|
||||
# We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
|
||||
|
@ -15,6 +15,16 @@ config EFI_LOADER
|
|||
interfaces to a loaded EFI application, enabling it to reuse U-Boot's
|
||||
device drivers.
|
||||
|
||||
config EFI_UNICODE_CAPITALIZATION
|
||||
bool "Support Unicode capitalization"
|
||||
depends on EFI_LOADER
|
||||
default y
|
||||
help
|
||||
Select this option to enable correct handling of the capitalization of
|
||||
Unicode codepoints in the range 0x0000-0xffff. If this option is not
|
||||
set, only the the correct handling of the letters of the codepage
|
||||
used by the FAT file system is ensured.
|
||||
|
||||
config EFI_LOADER_BOUNCE_BUFFER
|
||||
bool "EFI Applications use bounce buffers for DMA operations"
|
||||
depends on EFI_LOADER && ARM64
|
||||
|
|
|
@ -17,9 +17,19 @@ always += helloworld.efi
|
|||
endif
|
||||
|
||||
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
|
||||
obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
|
||||
obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
|
||||
obj-y += efi_device_path_utilities.o efi_file.o efi_variable.o efi_bootmgr.o
|
||||
obj-y += efi_bootmgr.o
|
||||
obj-y += efi_boottime.o
|
||||
obj-y += efi_console.o
|
||||
obj-y += efi_device_path.o
|
||||
obj-y += efi_device_path_to_text.o
|
||||
obj-y += efi_device_path_utilities.o
|
||||
obj-y += efi_file.o
|
||||
obj-y += efi_image_loader.o
|
||||
obj-y += efi_memory.o
|
||||
obj-y += efi_root_node.o
|
||||
obj-y += efi_runtime.o
|
||||
obj-y += efi_unicode_collation.o
|
||||
obj-y += efi_variable.o
|
||||
obj-y += efi_watchdog.o
|
||||
obj-$(CONFIG_LCD) += efi_gop.o
|
||||
obj-$(CONFIG_DM_VIDEO) += efi_gop.o
|
||||
|
|
|
@ -60,7 +60,7 @@ static void parse_load_option(struct load_option *lo, void *ptr)
|
|||
ptr += sizeof(u16);
|
||||
|
||||
lo->label = ptr;
|
||||
ptr += (utf16_strlen(lo->label) + 1) * 2;
|
||||
ptr += (u16_strlen(lo->label) + 1) * 2;
|
||||
|
||||
lo->file_path = ptr;
|
||||
ptr += lo->file_path_length;
|
||||
|
|
|
@ -26,14 +26,6 @@ LIST_HEAD(efi_obj_list);
|
|||
/* List of all events */
|
||||
LIST_HEAD(efi_events);
|
||||
|
||||
/*
|
||||
* If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
|
||||
* we need to do trickery with caches. Since we don't want to break the EFI
|
||||
* aware boot path, only apply hacks when loading exiting directly (breaking
|
||||
* direct Linux EFI booting along the way - oh well).
|
||||
*/
|
||||
static bool efi_is_direct_boot = true;
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
/*
|
||||
* The "gd" pointer lives in a register on ARM and AArch64 that we declare
|
||||
|
@ -105,8 +97,8 @@ void efi_save_gd(void)
|
|||
|
||||
/*
|
||||
* Special case handler for error/abort that just forces things back to u-boot
|
||||
* world so we can dump out an abort msg, without any care about returning back
|
||||
* to UEFI world.
|
||||
* world so we can dump out an abort message, without any care about returning
|
||||
* back to UEFI world.
|
||||
*/
|
||||
void efi_restore_gd(void)
|
||||
{
|
||||
|
@ -183,7 +175,7 @@ static void efi_queue_event(struct efi_event *event, bool check_tpl)
|
|||
* is_valid_tpl() - check if the task priority level is valid
|
||||
*
|
||||
* @tpl: TPL level to check
|
||||
* ReturnValue: status code
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t is_valid_tpl(efi_uintn_t tpl)
|
||||
{
|
||||
|
@ -626,7 +618,7 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl,
|
|||
evt->notify_function = notify_function;
|
||||
evt->notify_context = notify_context;
|
||||
evt->group = group;
|
||||
/* Disable timers on bootup */
|
||||
/* Disable timers on boot up */
|
||||
evt->trigger_next = -1ULL;
|
||||
evt->is_queued = false;
|
||||
evt->is_signaled = false;
|
||||
|
@ -732,7 +724,7 @@ void efi_timer_check(void)
|
|||
* efi_set_timer() - set the trigger time for a timer event or stop the event
|
||||
* @event: event for which the timer is set
|
||||
* @type: type of the timer
|
||||
* @trigger_time: trigger period in multiples of 100ns
|
||||
* @trigger_time: trigger period in multiples of 100 ns
|
||||
*
|
||||
* This is the function for internal usage in U-Boot. For the API function
|
||||
* implementing the SetTimer service see efi_set_timer_ext.
|
||||
|
@ -747,8 +739,8 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
|
|||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
/*
|
||||
* The parameter defines a multiple of 100ns.
|
||||
* We use multiples of 1000ns. So divide by 10.
|
||||
* The parameter defines a multiple of 100 ns.
|
||||
* We use multiples of 1000 ns. So divide by 10.
|
||||
*/
|
||||
do_div(trigger_time, 10);
|
||||
|
||||
|
@ -774,7 +766,7 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
|
|||
* event
|
||||
* @event: event for which the timer is set
|
||||
* @type: type of the timer
|
||||
* @trigger_time: trigger period in multiples of 100ns
|
||||
* @trigger_time: trigger period in multiples of 100 ns
|
||||
*
|
||||
* This function implements the SetTimer service.
|
||||
*
|
||||
|
@ -1061,7 +1053,7 @@ out:
|
|||
/**
|
||||
* efi_get_drivers() - get all drivers associated to a controller
|
||||
* @efiobj: handle of the controller
|
||||
* @protocol: protocol guid (optional)
|
||||
* @protocol: protocol GUID (optional)
|
||||
* @number_of_drivers: number of child controllers
|
||||
* @driver_handle_buffer: handles of the the drivers
|
||||
*
|
||||
|
@ -1126,7 +1118,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj,
|
|||
/**
|
||||
* efi_disconnect_all_drivers() - disconnect all drivers from a controller
|
||||
* @efiobj: handle of the controller
|
||||
* @protocol: protocol guid (optional)
|
||||
* @protocol: protocol GUID (optional)
|
||||
* @child_handle: handle of the child to destroy
|
||||
*
|
||||
* This function implements the DisconnectController service.
|
||||
|
@ -1408,7 +1400,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
|
|||
if (!guid)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
/* Check for guid override */
|
||||
/* Check for GUID override */
|
||||
for (i = 0; i < systab.nr_tables; i++) {
|
||||
if (!guidcmp(guid, &systab.tables[i].guid)) {
|
||||
if (table)
|
||||
|
@ -1432,7 +1424,7 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid,
|
|||
systab.nr_tables = i + 1;
|
||||
|
||||
out:
|
||||
/* systab.nr_tables may have changed. So we need to update the crc32 */
|
||||
/* systab.nr_tables may have changed. So we need to update the CRC32 */
|
||||
efi_update_table_header_crc32(&systab.hdr);
|
||||
|
||||
/* Notify that the configuration table was changed */
|
||||
|
@ -1478,20 +1470,35 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid,
|
|||
*
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_setup_loaded_image(
|
||||
struct efi_loaded_image *info, struct efi_object *obj,
|
||||
struct efi_device_path *device_path,
|
||||
struct efi_device_path *file_path)
|
||||
efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
|
||||
struct efi_device_path *file_path,
|
||||
struct efi_loaded_image_obj **handle_ptr,
|
||||
struct efi_loaded_image **info_ptr)
|
||||
{
|
||||
efi_status_t ret;
|
||||
struct efi_loaded_image *info;
|
||||
struct efi_loaded_image_obj *obj;
|
||||
|
||||
info = calloc(1, sizeof(*info));
|
||||
if (!info)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
obj = calloc(1, sizeof(*obj));
|
||||
if (!obj) {
|
||||
free(info);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
/* Add internal object to object list */
|
||||
efi_add_handle(obj);
|
||||
/* efi_exit() assumes that the handle points to the info */
|
||||
obj->handle = info;
|
||||
efi_add_handle(&obj->parent);
|
||||
|
||||
if (info_ptr)
|
||||
*info_ptr = info;
|
||||
if (handle_ptr)
|
||||
*handle_ptr = obj;
|
||||
|
||||
info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
|
||||
info->file_path = file_path;
|
||||
info->system_table = &systab;
|
||||
|
||||
if (device_path) {
|
||||
info->device_handle = efi_dp_find_obj(device_path, NULL);
|
||||
|
@ -1499,8 +1506,8 @@ efi_status_t efi_setup_loaded_image(
|
|||
* When asking for the device path interface, return
|
||||
* bootefi_device_path
|
||||
*/
|
||||
ret = efi_add_protocol(obj->handle, &efi_guid_device_path,
|
||||
device_path);
|
||||
ret = efi_add_protocol(obj->parent.handle,
|
||||
&efi_guid_device_path, device_path);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
}
|
||||
|
@ -1509,19 +1516,8 @@ efi_status_t efi_setup_loaded_image(
|
|||
* When asking for the loaded_image interface, just
|
||||
* return handle which points to loaded_image_info
|
||||
*/
|
||||
ret = efi_add_protocol(obj->handle, &efi_guid_loaded_image, info);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
ret = efi_add_protocol(obj->handle,
|
||||
&efi_guid_device_path_to_text_protocol,
|
||||
(void *)&efi_device_path_to_text);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
ret = efi_add_protocol(obj->handle,
|
||||
&efi_guid_device_path_utilities_protocol,
|
||||
(void *)&efi_device_path_utilities);
|
||||
ret = efi_add_protocol(obj->parent.handle,
|
||||
&efi_guid_loaded_image, info);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
|
@ -1604,7 +1600,8 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
|
|||
efi_handle_t *image_handle)
|
||||
{
|
||||
struct efi_loaded_image *info;
|
||||
struct efi_object *obj;
|
||||
struct efi_loaded_image_obj **image_obj =
|
||||
(struct efi_loaded_image_obj **)image_handle;
|
||||
efi_status_t ret;
|
||||
|
||||
EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image,
|
||||
|
@ -1620,18 +1617,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
|
|||
goto error;
|
||||
}
|
||||
|
||||
info = calloc(1, sizeof(*info));
|
||||
if (!info) {
|
||||
ret = EFI_OUT_OF_RESOURCES;
|
||||
goto error;
|
||||
}
|
||||
obj = calloc(1, sizeof(*obj));
|
||||
if (!obj) {
|
||||
free(info);
|
||||
ret = EFI_OUT_OF_RESOURCES;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!source_buffer) {
|
||||
struct efi_device_path *dp, *fp;
|
||||
|
||||
|
@ -1643,35 +1628,35 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy,
|
|||
* file parts:
|
||||
*/
|
||||
efi_dp_split_file_path(file_path, &dp, &fp);
|
||||
ret = efi_setup_loaded_image(info, obj, dp, fp);
|
||||
ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
} else {
|
||||
/* In this case, file_path is the "device" path, ie.
|
||||
/* In this case, file_path is the "device" path, i.e.
|
||||
* something like a HARDWARE_DEVICE:MEMORY_MAPPED
|
||||
*/
|
||||
ret = efi_setup_loaded_image(info, obj, file_path, NULL);
|
||||
ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
goto error;
|
||||
}
|
||||
info->reserved = efi_load_pe(source_buffer, info);
|
||||
if (!info->reserved) {
|
||||
(*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info);
|
||||
if (!(*image_obj)->entry) {
|
||||
ret = EFI_UNSUPPORTED;
|
||||
goto failure;
|
||||
}
|
||||
info->system_table = &systab;
|
||||
info->parent_handle = parent_image;
|
||||
*image_handle = obj->handle;
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
failure:
|
||||
efi_delete_handle(*image_handle);
|
||||
*image_handle = NULL;
|
||||
free(info);
|
||||
efi_delete_handle(obj);
|
||||
error:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_start_image() - dall the entry point of an image
|
||||
* efi_start_image() - call the entry point of an image
|
||||
* @image_handle: handle of the image
|
||||
* @exit_data_size: size of the buffer
|
||||
* @exit_data: buffer to receive the exit data of the called image
|
||||
|
@ -1687,18 +1672,14 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
|
|||
unsigned long *exit_data_size,
|
||||
s16 **exit_data)
|
||||
{
|
||||
EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
|
||||
struct efi_system_table *st);
|
||||
struct efi_loaded_image *info = image_handle;
|
||||
struct efi_loaded_image_obj *image_obj =
|
||||
(struct efi_loaded_image_obj *)image_handle;
|
||||
efi_status_t ret;
|
||||
|
||||
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
|
||||
entry = info->reserved;
|
||||
|
||||
efi_is_direct_boot = false;
|
||||
|
||||
/* call the image! */
|
||||
if (setjmp(&info->exit_jmp)) {
|
||||
if (setjmp(&image_obj->exit_jmp)) {
|
||||
/*
|
||||
* We called the entry point of the child image with EFI_CALL
|
||||
* in the lines below. The child image called the Exit() boot
|
||||
|
@ -1721,16 +1702,16 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
|
|||
assert(__efi_entry_check());
|
||||
debug("%sEFI: %lu returned by started image\n",
|
||||
__efi_nesting_dec(),
|
||||
(unsigned long)((uintptr_t)info->exit_status &
|
||||
(unsigned long)((uintptr_t)image_obj->exit_status &
|
||||
~EFI_ERROR_MASK));
|
||||
return EFI_EXIT(info->exit_status);
|
||||
return EFI_EXIT(image_obj->exit_status);
|
||||
}
|
||||
|
||||
ret = EFI_CALL(entry(image_handle, &systab));
|
||||
ret = EFI_CALL(image_obj->entry(image_handle, &systab));
|
||||
|
||||
/*
|
||||
* Usually UEFI applications call Exit() instead of returning.
|
||||
* But because the world doesn not consist of ponies and unicorns,
|
||||
* But because the world doesn't consist of ponies and unicorns,
|
||||
* we're happy to emulate that behavior on behalf of a payload
|
||||
* that forgot.
|
||||
*/
|
||||
|
@ -1757,17 +1738,11 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
|
|||
int16_t *exit_data)
|
||||
{
|
||||
/*
|
||||
* We require that the handle points to the original loaded
|
||||
* image protocol interface.
|
||||
*
|
||||
* For getting the longjmp address this is safer than locating
|
||||
* the protocol because the protocol may have been reinstalled
|
||||
* pointing to another memory location.
|
||||
*
|
||||
* TODO: We should call the unload procedure of the loaded
|
||||
* image protocol.
|
||||
*/
|
||||
struct efi_loaded_image *loaded_image_info = (void *)image_handle;
|
||||
struct efi_loaded_image_obj *image_obj =
|
||||
(struct efi_loaded_image_obj *)image_handle;
|
||||
|
||||
EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
|
||||
exit_data_size, exit_data);
|
||||
|
@ -1781,8 +1756,8 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
|
|||
*/
|
||||
efi_restore_gd();
|
||||
|
||||
loaded_image_info->exit_status = exit_status;
|
||||
longjmp(&loaded_image_info->exit_jmp, 1);
|
||||
image_obj->exit_status = exit_status;
|
||||
longjmp(&image_obj->exit_jmp, 1);
|
||||
|
||||
panic("EFI application exited");
|
||||
}
|
||||
|
@ -1810,21 +1785,6 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle)
|
|||
return EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_exit_caches() - fix up caches for EFI payloads if necessary
|
||||
*/
|
||||
static void efi_exit_caches(void)
|
||||
{
|
||||
#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
|
||||
/*
|
||||
* Grub on 32bit ARM needs to have caches disabled before jumping into
|
||||
* a zImage, but does not know of all cache layers. Give it a hand.
|
||||
*/
|
||||
if (efi_is_direct_boot)
|
||||
cleanup_before_linux();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_exit_boot_services() - stop all boot services
|
||||
* @image_handle: handle of the loaded image
|
||||
|
@ -1874,17 +1834,14 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO Should persist EFI variables here */
|
||||
/* TODO: Should persist EFI variables here */
|
||||
|
||||
board_quiesce_devices();
|
||||
|
||||
/* Fix up caches for EFI payloads if necessary */
|
||||
efi_exit_caches();
|
||||
|
||||
/* This stops all lingering devices */
|
||||
bootm_disable_interrupts();
|
||||
|
||||
/* Disable boottime services */
|
||||
/* Disable boot time services */
|
||||
systab.con_in_handle = NULL;
|
||||
systab.con_in = NULL;
|
||||
systab.con_out_handle = NULL;
|
||||
|
@ -2118,7 +2075,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle(
|
|||
++*protocol_buffer_count;
|
||||
}
|
||||
|
||||
/* Copy guids */
|
||||
/* Copy GUIDs */
|
||||
if (*protocol_buffer_count) {
|
||||
size_t j = 0;
|
||||
|
||||
|
@ -2709,7 +2666,7 @@ static efi_status_t efi_bind_controller(
|
|||
* efi_connect_single_controller() - connect a single driver to a controller
|
||||
* @controller_handle: controller
|
||||
* @driver_image_handle: driver
|
||||
* @remain_device_path: remainting path
|
||||
* @remain_device_path: remaining path
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
|
@ -2790,7 +2747,7 @@ static efi_status_t efi_connect_single_controller(
|
|||
* details.
|
||||
*
|
||||
* First all driver binding protocol handles are tried for binding drivers.
|
||||
* Afterwards all handles that have openened a protocol of the controller
|
||||
* Afterwards all handles that have opened a protocol of the controller
|
||||
* with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers.
|
||||
*
|
||||
* Return: status code
|
||||
|
@ -3123,7 +3080,7 @@ struct efi_system_table __efi_runtime_data systab = {
|
|||
/**
|
||||
* efi_initialize_system_table() - Initialize system table
|
||||
*
|
||||
* Return Value: status code
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_initialize_system_table(void)
|
||||
{
|
||||
|
@ -3135,7 +3092,7 @@ efi_status_t efi_initialize_system_table(void)
|
|||
sizeof(struct efi_configuration_table),
|
||||
(void **)&systab.tables);
|
||||
|
||||
/* Set crc32 field in table headers */
|
||||
/* Set CRC32 field in table headers */
|
||||
efi_update_table_header_crc32(&systab.hdr);
|
||||
efi_update_table_header_crc32(&efi_runtime_services.hdr);
|
||||
efi_update_table_header_crc32(&efi_boot_services.hdr);
|
||||
|
|
|
@ -42,10 +42,12 @@ static struct cout_mode efi_cout_modes[] = {
|
|||
},
|
||||
};
|
||||
|
||||
const efi_guid_t efi_guid_text_output_protocol =
|
||||
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
|
||||
const efi_guid_t efi_guid_text_input_ex_protocol =
|
||||
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
|
||||
const efi_guid_t efi_guid_text_input_protocol =
|
||||
EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
|
||||
const efi_guid_t efi_guid_text_output_protocol =
|
||||
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
|
||||
|
||||
#define cESC '\x1b'
|
||||
#define ESC "\x1b"
|
||||
|
@ -111,23 +113,28 @@ static efi_status_t EFIAPI efi_cout_output_string(
|
|||
{
|
||||
struct simple_text_output_mode *con = &efi_con_mode;
|
||||
struct cout_mode *mode = &efi_cout_modes[con->mode];
|
||||
char *buf, *pos;
|
||||
u16 *p;
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p, %p", this, string);
|
||||
|
||||
unsigned int n16 = utf16_strlen(string);
|
||||
char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
|
||||
u16 *p;
|
||||
|
||||
*utf16_to_utf8((u8 *)buf, string, n16) = '\0';
|
||||
|
||||
buf = malloc(utf16_utf8_strlen(string) + 1);
|
||||
if (!buf) {
|
||||
ret = EFI_OUT_OF_RESOURCES;
|
||||
goto out;
|
||||
}
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, string);
|
||||
fputs(stdout, buf);
|
||||
free(buf);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* U+0007 (BEL) and U+0009 (TAB), have to increase the column by one.
|
||||
*/
|
||||
for (p = string; *p; ++p) {
|
||||
switch (*p) {
|
||||
|
@ -158,7 +165,8 @@ static efi_status_t EFIAPI efi_cout_output_string(
|
|||
con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
|
||||
}
|
||||
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
static efi_status_t EFIAPI efi_cout_test_string(
|
||||
|
@ -177,32 +185,56 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
|
|||
return (mode->rows == rows) && (mode->columns == 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
|
||||
*/
|
||||
static int query_console_serial(int *rows, int *cols)
|
||||
{
|
||||
/* Ask the terminal about its size */
|
||||
int n[3];
|
||||
int ret = 0;
|
||||
int n[2];
|
||||
u64 timeout;
|
||||
|
||||
/* Empty input buffer */
|
||||
while (tstc())
|
||||
getc();
|
||||
|
||||
printf(ESC"[18t");
|
||||
/*
|
||||
* Not all terminals understand CSI [18t for querying the console size.
|
||||
* We should adhere to escape sequences documented in the console_codes
|
||||
* manpage and the ECMA-48 standard.
|
||||
*
|
||||
* So here we follow a different approach. We position the cursor to the
|
||||
* bottom right and query its position. Before leaving the function we
|
||||
* restore the original cursor position.
|
||||
*/
|
||||
printf(ESC "7" /* Save cursor position */
|
||||
ESC "[r" /* Set scrolling region to full window */
|
||||
ESC "[999;999H" /* Move to bottom right corner */
|
||||
ESC "[6n"); /* Query cursor position */
|
||||
|
||||
/* Check if we have a terminal that understands */
|
||||
/* Allow up to one second for a response */
|
||||
timeout = timer_get_us() + 1000000;
|
||||
while (!tstc())
|
||||
if (timer_get_us() > timeout)
|
||||
return -1;
|
||||
if (timer_get_us() > timeout) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read {depth,rows,cols} */
|
||||
if (term_read_reply(n, 3, 't'))
|
||||
return -1;
|
||||
/* Read {rows,cols} */
|
||||
if (term_read_reply(n, 2, 'R')) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*cols = n[2];
|
||||
*rows = n[1];
|
||||
|
||||
return 0;
|
||||
*cols = n[1];
|
||||
*rows = n[0];
|
||||
out:
|
||||
printf(ESC "8"); /* Restore cursor position */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -298,8 +330,8 @@ static const struct {
|
|||
{ 36, 46 }, /* 3: cyan */
|
||||
{ 31, 41 }, /* 4: red */
|
||||
{ 35, 45 }, /* 5: magenta */
|
||||
{ 33, 43 }, /* 6: brown, map to yellow as edk2 does*/
|
||||
{ 37, 47 }, /* 7: light grey, map to white */
|
||||
{ 33, 43 }, /* 6: brown, map to yellow as EDK2 does*/
|
||||
{ 37, 47 }, /* 7: light gray, map to white */
|
||||
};
|
||||
|
||||
/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
|
||||
|
@ -351,13 +383,31 @@ static efi_status_t EFIAPI efi_cout_set_cursor_position(
|
|||
struct efi_simple_text_output_protocol *this,
|
||||
unsigned long column, unsigned long row)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
struct simple_text_output_mode *con = &efi_con_mode;
|
||||
struct cout_mode *mode = &efi_cout_modes[con->mode];
|
||||
|
||||
EFI_ENTRY("%p, %ld, %ld", this, column, row);
|
||||
|
||||
printf(ESC"[%d;%df", (int)row, (int)column);
|
||||
/* Check parameters */
|
||||
if (!this) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
if (row >= mode->rows || column >= mode->columns) {
|
||||
ret = EFI_UNSUPPORTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set cursor position by sending CSI H.
|
||||
* EFI origin is [0, 0], terminal origin is [1, 1].
|
||||
*/
|
||||
printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
|
||||
efi_con_mode.cursor_column = column;
|
||||
efi_con_mode.cursor_row = row;
|
||||
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
static efi_status_t EFIAPI efi_cout_enable_cursor(
|
||||
|
@ -384,29 +434,58 @@ struct efi_simple_text_output_protocol efi_con_out = {
|
|||
.mode = (void*)&efi_con_mode,
|
||||
};
|
||||
|
||||
static efi_status_t EFIAPI efi_cin_reset(
|
||||
struct efi_simple_input_interface *this,
|
||||
bool extended_verification)
|
||||
/**
|
||||
* struct efi_cin_notify_function - registered console input notify function
|
||||
*
|
||||
* @link: link to list
|
||||
* @data: key to notify
|
||||
* @function: function to call
|
||||
*/
|
||||
struct efi_cin_notify_function {
|
||||
struct list_head link;
|
||||
struct efi_key_data key;
|
||||
efi_status_t (EFIAPI *function)
|
||||
(struct efi_key_data *key_data);
|
||||
};
|
||||
|
||||
static bool key_available;
|
||||
static struct efi_key_data next_key;
|
||||
static LIST_HEAD(cin_notify_functions);
|
||||
|
||||
/**
|
||||
* set_shift_mask() - set shift mask
|
||||
*
|
||||
* @mod: Xterm shift mask
|
||||
*/
|
||||
void set_shift_mask(int mod, struct efi_key_state *key_state)
|
||||
{
|
||||
EFI_ENTRY("%p, %d", this, extended_verification);
|
||||
|
||||
/* Empty input buffer */
|
||||
while (tstc())
|
||||
getc();
|
||||
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
|
||||
if (mod) {
|
||||
--mod;
|
||||
if (mod & 1)
|
||||
key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
|
||||
if (mod & 2)
|
||||
key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
|
||||
if (mod & 4)
|
||||
key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
|
||||
if (mod & 8)
|
||||
key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
|
||||
} else {
|
||||
key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze modifiers (shift, alt, ctrl) for function keys.
|
||||
/**
|
||||
* analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
|
||||
*
|
||||
* This gets called when we have already parsed CSI.
|
||||
*
|
||||
* @modifiers: bitmask (shift, alt, ctrl)
|
||||
* @return: the unmodified code
|
||||
*/
|
||||
static char skip_modifiers(int *modifiers)
|
||||
static int analyze_modifiers(struct efi_key_state *key_state)
|
||||
{
|
||||
char c, mod = 0, ret = 0;
|
||||
int c, mod = 0, ret = 0;
|
||||
|
||||
c = getc();
|
||||
|
||||
|
@ -430,37 +509,38 @@ static char skip_modifiers(int *modifiers)
|
|||
}
|
||||
}
|
||||
out:
|
||||
if (mod)
|
||||
--mod;
|
||||
if (modifiers)
|
||||
*modifiers = mod;
|
||||
set_shift_mask(mod, key_state);
|
||||
if (!ret)
|
||||
ret = c;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static efi_status_t EFIAPI efi_cin_read_key_stroke(
|
||||
struct efi_simple_input_interface *this,
|
||||
struct efi_input_key *key)
|
||||
/**
|
||||
* efi_cin_read_key() - read a key from the console input
|
||||
*
|
||||
* @key: - key received
|
||||
* Return: - status code
|
||||
*/
|
||||
static efi_status_t efi_cin_read_key(struct efi_key_data *key)
|
||||
{
|
||||
struct efi_input_key pressed_key = {
|
||||
.scan_code = 0,
|
||||
.unicode_char = 0,
|
||||
};
|
||||
char ch;
|
||||
s32 ch;
|
||||
|
||||
EFI_ENTRY("%p, %p", this, key);
|
||||
if (console_read_unicode(&ch))
|
||||
return EFI_NOT_READY;
|
||||
|
||||
/* We don't do interrupts, so check for timers cooperatively */
|
||||
efi_timer_check();
|
||||
key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
|
||||
key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
|
||||
|
||||
if (!tstc()) {
|
||||
/* No key pressed */
|
||||
return EFI_EXIT(EFI_NOT_READY);
|
||||
}
|
||||
/* We do not support multi-word codes */
|
||||
if (ch >= 0x10000)
|
||||
ch = '?';
|
||||
|
||||
ch = getc();
|
||||
if (ch == cESC) {
|
||||
switch (ch) {
|
||||
case 0x1b:
|
||||
/*
|
||||
* Xterm Control Sequences
|
||||
* https://www.xfree86.org/4.8.0/ctlseqs.html
|
||||
|
@ -472,14 +552,13 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
|
|||
break;
|
||||
case 'O': /* F1 - F4 */
|
||||
ch = getc();
|
||||
/* skip modifiers */
|
||||
if (ch <= '9')
|
||||
/* consider modifiers */
|
||||
if (ch < 'P') {
|
||||
set_shift_mask(ch - '0', &key->key_state);
|
||||
ch = getc();
|
||||
}
|
||||
pressed_key.scan_code = ch - 'P' + 11;
|
||||
break;
|
||||
case 'a'...'z':
|
||||
ch = ch - 'a';
|
||||
break;
|
||||
case '[':
|
||||
ch = getc();
|
||||
switch (ch) {
|
||||
|
@ -493,7 +572,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
|
|||
pressed_key.scan_code = 5;
|
||||
break;
|
||||
case '1':
|
||||
ch = skip_modifiers(NULL);
|
||||
ch = analyze_modifiers(&key->key_state);
|
||||
switch (ch) {
|
||||
case '1'...'5': /* F1 - F5 */
|
||||
pressed_key.scan_code = ch - '1' + 11;
|
||||
|
@ -513,7 +592,7 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
|
|||
}
|
||||
break;
|
||||
case '2':
|
||||
ch = skip_modifiers(NULL);
|
||||
ch = analyze_modifiers(&key->key_state);
|
||||
switch (ch) {
|
||||
case '0'...'1': /* F9 - F10 */
|
||||
pressed_key.scan_code = ch - '0' + 19;
|
||||
|
@ -528,31 +607,406 @@ static efi_status_t EFIAPI efi_cin_read_key_stroke(
|
|||
break;
|
||||
case '3': /* DEL */
|
||||
pressed_key.scan_code = 8;
|
||||
skip_modifiers(NULL);
|
||||
analyze_modifiers(&key->key_state);
|
||||
break;
|
||||
case '5': /* PG UP */
|
||||
pressed_key.scan_code = 9;
|
||||
skip_modifiers(NULL);
|
||||
analyze_modifiers(&key->key_state);
|
||||
break;
|
||||
case '6': /* PG DOWN */
|
||||
pressed_key.scan_code = 10;
|
||||
skip_modifiers(NULL);
|
||||
analyze_modifiers(&key->key_state);
|
||||
break;
|
||||
}
|
||||
} /* [ */
|
||||
break;
|
||||
default:
|
||||
/* ALT key */
|
||||
set_shift_mask(3, &key->key_state);
|
||||
}
|
||||
} else if (ch == 0x7f) {
|
||||
break;
|
||||
case 0x7f:
|
||||
/* Backspace */
|
||||
ch = 0x08;
|
||||
}
|
||||
if (!pressed_key.scan_code)
|
||||
if (pressed_key.scan_code) {
|
||||
key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
|
||||
} else {
|
||||
pressed_key.unicode_char = ch;
|
||||
*key = pressed_key;
|
||||
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
/*
|
||||
* Assume left control key for control characters typically
|
||||
* entered using the control key.
|
||||
*/
|
||||
if (ch >= 0x01 && ch <= 0x1f) {
|
||||
key->key_state.key_shift_state |=
|
||||
EFI_SHIFT_STATE_VALID;
|
||||
switch (ch) {
|
||||
case 0x01 ... 0x07:
|
||||
case 0x0b ... 0x0c:
|
||||
case 0x0e ... 0x1f:
|
||||
key->key_state.key_shift_state |=
|
||||
EFI_LEFT_CONTROL_PRESSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
key->key = pressed_key;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
struct efi_simple_input_interface efi_con_in = {
|
||||
/**
|
||||
* efi_cin_notify() - notify registered functions
|
||||
*/
|
||||
static void efi_cin_notify(void)
|
||||
{
|
||||
struct efi_cin_notify_function *item;
|
||||
|
||||
list_for_each_entry(item, &cin_notify_functions, link) {
|
||||
bool match = true;
|
||||
|
||||
/* We do not support toggle states */
|
||||
if (item->key.key.unicode_char || item->key.key.scan_code) {
|
||||
if (item->key.key.unicode_char !=
|
||||
next_key.key.unicode_char ||
|
||||
item->key.key.scan_code != next_key.key.scan_code)
|
||||
match = false;
|
||||
}
|
||||
if (item->key.key_state.key_shift_state &&
|
||||
item->key.key_state.key_shift_state !=
|
||||
next_key.key_state.key_shift_state)
|
||||
match = false;
|
||||
|
||||
if (match)
|
||||
/* We don't bother about the return code */
|
||||
EFI_CALL(item->function(&next_key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_check() - check if keyboard input is available
|
||||
*/
|
||||
static void efi_cin_check(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
if (key_available) {
|
||||
efi_signal_event(efi_con_in.wait_for_key, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tstc()) {
|
||||
ret = efi_cin_read_key(&next_key);
|
||||
if (ret == EFI_SUCCESS) {
|
||||
key_available = true;
|
||||
|
||||
/* Notify registered functions */
|
||||
efi_cin_notify();
|
||||
|
||||
/* Queue the wait for key event */
|
||||
if (key_available)
|
||||
efi_signal_event(efi_con_in.wait_for_key, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_empty_buffer() - empty input buffer
|
||||
*/
|
||||
static void efi_cin_empty_buffer(void)
|
||||
{
|
||||
while (tstc())
|
||||
getc();
|
||||
key_available = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_reset_ex() - reset console input
|
||||
*
|
||||
* @this: - the extended simple text input protocol
|
||||
* @extended_verification: - extended verification
|
||||
*
|
||||
* This function implements the reset service of the
|
||||
* EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*
|
||||
* Return: old value of the task priority level
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_cin_reset_ex(
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
bool extended_verification)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p, %d", this, extended_verification);
|
||||
|
||||
/* Check parameters */
|
||||
if (!this) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
efi_cin_empty_buffer();
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_read_key_stroke_ex() - read key stroke
|
||||
*
|
||||
* @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||
* @key_data: key read from console
|
||||
* Return: status code
|
||||
*
|
||||
* This function implements the ReadKeyStrokeEx service of the
|
||||
* EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
struct efi_key_data *key_data)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p, %p", this, key_data);
|
||||
|
||||
/* Check parameters */
|
||||
if (!this || !key_data) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We don't do interrupts, so check for timers cooperatively */
|
||||
efi_timer_check();
|
||||
|
||||
/* Enable console input after ExitBootServices */
|
||||
efi_cin_check();
|
||||
|
||||
if (!key_available) {
|
||||
ret = EFI_NOT_READY;
|
||||
goto out;
|
||||
}
|
||||
*key_data = next_key;
|
||||
key_available = false;
|
||||
efi_con_in.wait_for_key->is_signaled = false;
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_set_state() - set toggle key state
|
||||
*
|
||||
* @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||
* @key_toggle_state: key toggle state
|
||||
* Return: status code
|
||||
*
|
||||
* This function implements the SetState service of the
|
||||
* EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_cin_set_state(
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
u8 key_toggle_state)
|
||||
{
|
||||
EFI_ENTRY("%p, %u", this, key_toggle_state);
|
||||
/*
|
||||
* U-Boot supports multiple console input sources like serial and
|
||||
* net console for which a key toggle state cannot be set at all.
|
||||
*
|
||||
* According to the UEFI specification it is allowable to not implement
|
||||
* this service.
|
||||
*/
|
||||
return EFI_EXIT(EFI_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_register_key_notify() - register key notification function
|
||||
*
|
||||
* @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||
* @key_data: key to be notified
|
||||
* @key_notify_function: function to be called if the key is pressed
|
||||
* @notify_handle: handle for unregistering the notification
|
||||
* Return: status code
|
||||
*
|
||||
* This function implements the SetState service of the
|
||||
* EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_cin_register_key_notify(
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
struct efi_key_data *key_data,
|
||||
efi_status_t (EFIAPI *key_notify_function)(
|
||||
struct efi_key_data *key_data),
|
||||
void **notify_handle)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
struct efi_cin_notify_function *notify_function;
|
||||
|
||||
EFI_ENTRY("%p, %p, %p, %p",
|
||||
this, key_data, key_notify_function, notify_handle);
|
||||
|
||||
/* Check parameters */
|
||||
if (!this || !key_data || !key_notify_function || !notify_handle) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
|
||||
key_data->key.unicode_char,
|
||||
key_data->key.scan_code,
|
||||
key_data->key_state.key_shift_state,
|
||||
key_data->key_state.key_toggle_state);
|
||||
|
||||
notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
|
||||
if (!notify_function) {
|
||||
ret = EFI_OUT_OF_RESOURCES;
|
||||
goto out;
|
||||
}
|
||||
notify_function->key = *key_data;
|
||||
notify_function->function = key_notify_function;
|
||||
list_add_tail(¬ify_function->link, &cin_notify_functions);
|
||||
*notify_handle = notify_function;
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_unregister_key_notify() - unregister key notification function
|
||||
*
|
||||
* @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||
* @notification_handle: handle received when registering
|
||||
* Return: status code
|
||||
*
|
||||
* This function implements the SetState service of the
|
||||
* EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_cin_unregister_key_notify(
|
||||
struct efi_simple_text_input_ex_protocol *this,
|
||||
void *notification_handle)
|
||||
{
|
||||
efi_status_t ret = EFI_INVALID_PARAMETER;
|
||||
struct efi_cin_notify_function *item, *notify_function =
|
||||
notification_handle;
|
||||
|
||||
EFI_ENTRY("%p, %p", this, notification_handle);
|
||||
|
||||
/* Check parameters */
|
||||
if (!this || !notification_handle)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(item, &cin_notify_functions, link) {
|
||||
if (item == notify_function) {
|
||||
ret = EFI_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto out;
|
||||
|
||||
/* Remove the notify function */
|
||||
list_del(¬ify_function->link);
|
||||
free(notify_function);
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* efi_cin_reset() - drain the input buffer
|
||||
*
|
||||
* @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||
* @extended_verification: allow for exhaustive verification
|
||||
* Return: status code
|
||||
*
|
||||
* This function implements the Reset service of the
|
||||
* EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_cin_reset
|
||||
(struct efi_simple_text_input_protocol *this,
|
||||
bool extended_verification)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p, %d", this, extended_verification);
|
||||
|
||||
/* Check parameters */
|
||||
if (!this) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
efi_cin_empty_buffer();
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_cin_read_key_stroke() - read key stroke
|
||||
*
|
||||
* @this: instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||
* @key: key read from console
|
||||
* Return: status code
|
||||
*
|
||||
* This function implements the ReadKeyStroke service of the
|
||||
* EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_cin_read_key_stroke
|
||||
(struct efi_simple_text_input_protocol *this,
|
||||
struct efi_input_key *key)
|
||||
{
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p, %p", this, key);
|
||||
|
||||
/* Check parameters */
|
||||
if (!this || !key) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We don't do interrupts, so check for timers cooperatively */
|
||||
efi_timer_check();
|
||||
|
||||
/* Enable console input after ExitBootServices */
|
||||
efi_cin_check();
|
||||
|
||||
if (!key_available) {
|
||||
ret = EFI_NOT_READY;
|
||||
goto out;
|
||||
}
|
||||
*key = next_key.key;
|
||||
key_available = false;
|
||||
efi_con_in.wait_for_key->is_signaled = false;
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
|
||||
.reset = efi_cin_reset_ex,
|
||||
.read_key_stroke_ex = efi_cin_read_key_stroke_ex,
|
||||
.wait_for_key_ex = NULL,
|
||||
.set_state = efi_cin_set_state,
|
||||
.register_key_notify = efi_cin_register_key_notify,
|
||||
.unregister_key_notify = efi_cin_unregister_key_notify,
|
||||
};
|
||||
|
||||
struct efi_simple_text_input_protocol efi_con_in = {
|
||||
.reset = efi_cin_reset,
|
||||
.read_key_stroke = efi_cin_read_key_stroke,
|
||||
.wait_for_key = NULL,
|
||||
|
@ -560,31 +1014,38 @@ struct efi_simple_input_interface efi_con_in = {
|
|||
|
||||
static struct efi_event *console_timer_event;
|
||||
|
||||
static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Notification function of the console timer event.
|
||||
* efi_console_timer_notify() - notify the console timer event
|
||||
*
|
||||
* event: console timer event
|
||||
* context: not used
|
||||
* @event: console timer event
|
||||
* @context: not used
|
||||
*/
|
||||
static void EFIAPI efi_console_timer_notify(struct efi_event *event,
|
||||
void *context)
|
||||
{
|
||||
EFI_ENTRY("%p, %p", event, context);
|
||||
|
||||
/* Check if input is available */
|
||||
if (tstc()) {
|
||||
/* Queue the wait for key event */
|
||||
efi_con_in.wait_for_key->is_signaled = true;
|
||||
efi_signal_event(efi_con_in.wait_for_key, true);
|
||||
}
|
||||
efi_cin_check();
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
/* This gets called from do_bootefi_exec(). */
|
||||
/**
|
||||
* efi_key_notify() - notify the wait for key event
|
||||
*
|
||||
* @event: wait for key event
|
||||
* @context: not used
|
||||
*/
|
||||
static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
|
||||
{
|
||||
EFI_ENTRY("%p, %p", event, context);
|
||||
efi_cin_check();
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_console_register() - install the console protocols
|
||||
*
|
||||
* This function is called from do_bootefi_exec().
|
||||
*/
|
||||
int efi_console_register(void)
|
||||
{
|
||||
efi_status_t r;
|
||||
|
@ -598,17 +1059,27 @@ int efi_console_register(void)
|
|||
r = efi_create_handle((efi_handle_t *)&efi_console_output_obj);
|
||||
if (r != EFI_SUCCESS)
|
||||
goto out_of_memory;
|
||||
|
||||
r = efi_add_protocol(efi_console_output_obj->handle,
|
||||
&efi_guid_text_output_protocol, &efi_con_out);
|
||||
if (r != EFI_SUCCESS)
|
||||
goto out_of_memory;
|
||||
systab.con_out_handle = efi_console_output_obj->handle;
|
||||
systab.stderr_handle = efi_console_output_obj->handle;
|
||||
|
||||
r = efi_create_handle((efi_handle_t *)&efi_console_input_obj);
|
||||
if (r != EFI_SUCCESS)
|
||||
goto out_of_memory;
|
||||
|
||||
r = efi_add_protocol(efi_console_input_obj->handle,
|
||||
&efi_guid_text_input_protocol, &efi_con_in);
|
||||
if (r != EFI_SUCCESS)
|
||||
goto out_of_memory;
|
||||
systab.con_in_handle = efi_console_input_obj->handle;
|
||||
r = efi_add_protocol(efi_console_input_obj->handle,
|
||||
&efi_guid_text_input_ex_protocol, &efi_con_in_ex);
|
||||
if (r != EFI_SUCCESS)
|
||||
goto out_of_memory;
|
||||
|
||||
/* Create console events */
|
||||
r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
|
||||
|
@ -617,6 +1088,7 @@ int efi_console_register(void)
|
|||
printf("ERROR: Failed to register WaitForKey event\n");
|
||||
return r;
|
||||
}
|
||||
efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
|
||||
r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
|
||||
efi_console_timer_notify, NULL, NULL,
|
||||
&console_timer_event);
|
||||
|
@ -630,6 +1102,6 @@ int efi_console_register(void)
|
|||
printf("ERROR: Failed to set console timer\n");
|
||||
return r;
|
||||
out_of_memory:
|
||||
printf("ERROR: Out of meemory\n");
|
||||
printf("ERROR: Out of memory\n");
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -22,10 +22,6 @@ static const struct efi_device_path END = {
|
|||
.length = sizeof(END),
|
||||
};
|
||||
|
||||
#define U_BOOT_GUID \
|
||||
EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
|
||||
0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
|
||||
|
||||
/* template ROOT node: */
|
||||
static const struct efi_device_path_vendor ROOT = {
|
||||
.dp = {
|
||||
|
|
|
@ -17,6 +17,15 @@
|
|||
const efi_guid_t efi_guid_device_path_to_text_protocol =
|
||||
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
|
||||
|
||||
/**
|
||||
* efi_str_to_u16() - convert ASCII string to UTF-16
|
||||
*
|
||||
* A u16 buffer is allocated from pool. The ASCII string is copied to the u16
|
||||
* buffer.
|
||||
*
|
||||
* @str: ASCII string
|
||||
* Return: UTF-16 string. NULL if out of memory.
|
||||
*/
|
||||
static u16 *efi_str_to_u16(char *str)
|
||||
{
|
||||
efi_uintn_t len;
|
||||
|
@ -29,7 +38,6 @@ static u16 *efi_str_to_u16(char *str)
|
|||
if (ret != EFI_SUCCESS)
|
||||
return NULL;
|
||||
ascii2unicode(out, str);
|
||||
out[len - 1] = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <charset.h>
|
||||
#include <efi_loader.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <fs.h>
|
||||
|
||||
/* GUID for file system information */
|
||||
|
@ -126,11 +127,22 @@ static int sanitize_path(char *path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* NOTE: despite what you would expect, 'file_name' is actually a path.
|
||||
* With windoze style backlashes, ofc.
|
||||
/**
|
||||
* file_open() - open a file handle
|
||||
*
|
||||
* @fs: file system
|
||||
* @parent: directory relative to which the file is to be opened
|
||||
* @file_name: path of the file to be opened. '\', '.', or '..' may
|
||||
* be used as modifiers. A leading backslash indicates an
|
||||
* absolute path.
|
||||
* @mode: bit mask indicating the access mode (read, write,
|
||||
* create)
|
||||
* @attributes: attributes for newly created file
|
||||
* Returns: handle to the opened file or NULL
|
||||
*/
|
||||
static struct efi_file_handle *file_open(struct file_system *fs,
|
||||
struct file_handle *parent, s16 *file_name, u64 mode)
|
||||
struct file_handle *parent, s16 *file_name, u64 mode,
|
||||
u64 attributes)
|
||||
{
|
||||
struct file_handle *fh;
|
||||
char f0[MAX_UTF8_PER_UTF16] = {0};
|
||||
|
@ -139,7 +151,7 @@ static struct efi_file_handle *file_open(struct file_system *fs,
|
|||
|
||||
if (file_name) {
|
||||
utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1);
|
||||
flen = utf16_strlen((u16 *)file_name);
|
||||
flen = u16_strlen((u16 *)file_name);
|
||||
}
|
||||
|
||||
/* we could have a parent, but also an absolute path: */
|
||||
|
@ -173,7 +185,12 @@ static struct efi_file_handle *file_open(struct file_system *fs,
|
|||
if (set_blk_dev(fh))
|
||||
goto error;
|
||||
|
||||
if (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path)))
|
||||
if ((mode & EFI_FILE_MODE_CREATE) &&
|
||||
(attributes & EFI_FILE_DIRECTORY)) {
|
||||
if (fs_mkdir(fh->path))
|
||||
goto error;
|
||||
} else if (!((mode & EFI_FILE_MODE_CREATE) ||
|
||||
fs_exists(fh->path)))
|
||||
goto error;
|
||||
|
||||
/* figure out if file is a directory: */
|
||||
|
@ -195,15 +212,46 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
|
|||
s16 *file_name, u64 open_mode, u64 attributes)
|
||||
{
|
||||
struct file_handle *fh = to_fh(file);
|
||||
efi_status_t ret;
|
||||
|
||||
EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name,
|
||||
open_mode, attributes);
|
||||
|
||||
*new_handle = file_open(fh->fs, fh, file_name, open_mode);
|
||||
if (!*new_handle)
|
||||
return EFI_EXIT(EFI_NOT_FOUND);
|
||||
/* Check parameters */
|
||||
if (!file || !new_handle || !file_name) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
if (open_mode != EFI_FILE_MODE_READ &&
|
||||
open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE) &&
|
||||
open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
|
||||
EFI_FILE_MODE_CREATE)) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* The UEFI spec requires that attributes are only set in create mode.
|
||||
* The SCT does not care about this and sets EFI_FILE_DIRECTORY in
|
||||
* read mode. EDK2 does not check that attributes are zero if not in
|
||||
* create mode.
|
||||
*
|
||||
* So here we only check attributes in create mode and do not check
|
||||
* that they are zero otherwise.
|
||||
*/
|
||||
if ((open_mode & EFI_FILE_MODE_CREATE) &&
|
||||
(attributes & (EFI_FILE_READ_ONLY | ~EFI_FILE_VALID_ATTR))) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
/* Open file */
|
||||
*new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes);
|
||||
if (*new_handle)
|
||||
ret = EFI_SUCCESS;
|
||||
else
|
||||
ret = EFI_NOT_FOUND;
|
||||
out:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
static efi_status_t file_close(struct file_handle *fh)
|
||||
|
@ -223,9 +271,21 @@ static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
|
|||
static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
|
||||
{
|
||||
struct file_handle *fh = to_fh(file);
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p", file);
|
||||
|
||||
if (set_blk_dev(fh)) {
|
||||
ret = EFI_DEVICE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fs_unlink(fh->path))
|
||||
ret = EFI_DEVICE_ERROR;
|
||||
file_close(fh);
|
||||
return EFI_EXIT(EFI_WARN_DELETE_FAILURE);
|
||||
|
||||
error:
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
|
||||
|
@ -233,7 +293,7 @@ static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
|
|||
{
|
||||
loff_t actread;
|
||||
|
||||
if (fs_read(fh->path, (ulong)buffer, fh->offset,
|
||||
if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset,
|
||||
*buffer_size, &actread))
|
||||
return EFI_DEVICE_ERROR;
|
||||
|
||||
|
@ -363,7 +423,7 @@ static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size,
|
||||
if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size,
|
||||
&actwrite)) {
|
||||
ret = EFI_DEVICE_ERROR;
|
||||
goto error;
|
||||
|
@ -438,7 +498,7 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
|
|||
struct file_handle *fh = to_fh(file);
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
|
||||
EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer);
|
||||
EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer);
|
||||
|
||||
if (!guidcmp(info_type, &efi_file_info_guid)) {
|
||||
struct efi_file_info *info = buffer;
|
||||
|
@ -598,7 +658,7 @@ efi_open_volume(struct efi_simple_file_system_protocol *this,
|
|||
|
||||
EFI_ENTRY("%p, %p", this, root);
|
||||
|
||||
*root = file_open(fs, NULL, NULL, 0);
|
||||
*root = file_open(fs, NULL, NULL, 0, 0);
|
||||
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -48,20 +48,21 @@ static int machines[] = {
|
|||
* If the program counter is located within the image the offset to the base
|
||||
* address is shown.
|
||||
*
|
||||
* @obj: EFI object
|
||||
* @image: loaded image
|
||||
* @pc: program counter (use NULL to suppress offset output)
|
||||
* @return: status code
|
||||
*/
|
||||
efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc)
|
||||
static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj,
|
||||
struct efi_loaded_image *image,
|
||||
void *pc)
|
||||
{
|
||||
if (!image)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
printf("UEFI image");
|
||||
printf(" [0x%p:0x%p]",
|
||||
image->reloc_base, image->reloc_base + image->reloc_size - 1);
|
||||
if (pc && pc >= image->reloc_base &&
|
||||
pc < image->reloc_base + image->reloc_size)
|
||||
printf(" pc=0x%zx", pc - image->reloc_base);
|
||||
obj->reloc_base, obj->reloc_base + obj->reloc_size - 1);
|
||||
if (pc && pc >= obj->reloc_base &&
|
||||
pc < obj->reloc_base + obj->reloc_size)
|
||||
printf(" pc=0x%zx", pc - obj->reloc_base);
|
||||
if (image->file_path)
|
||||
printf(" '%pD'", image->file_path);
|
||||
printf("\n");
|
||||
|
@ -82,6 +83,7 @@ void efi_print_image_infos(void *pc)
|
|||
list_for_each_entry(handler, &efiobj->protocols, link) {
|
||||
if (!guidcmp(handler->guid, &efi_guid_loaded_image)) {
|
||||
efi_print_image_info(
|
||||
(struct efi_loaded_image_obj *)efiobj,
|
||||
handler->protocol_interface, pc);
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +198,8 @@ static void efi_set_code_and_data_type(
|
|||
* piece of memory. On successful load it then returns the entry point for
|
||||
* the binary. Otherwise NULL.
|
||||
*/
|
||||
void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
|
||||
void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
|
||||
struct efi_loaded_image *loaded_image_info)
|
||||
{
|
||||
IMAGE_NT_HEADERS32 *nt;
|
||||
IMAGE_DOS_HEADER *dos;
|
||||
|
@ -314,8 +317,8 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
|
|||
/* Populate the loaded image interface bits */
|
||||
loaded_image_info->image_base = efi;
|
||||
loaded_image_info->image_size = image_size;
|
||||
loaded_image_info->reloc_base = efi_reloc;
|
||||
loaded_image_info->reloc_size = virt_size;
|
||||
handle->reloc_base = efi_reloc;
|
||||
handle->reloc_size = virt_size;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
|
|
@ -65,9 +65,54 @@ static int efi_mem_cmp(void *priv, struct list_head *a, struct list_head *b)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static uint64_t desc_get_end(struct efi_mem_desc *desc)
|
||||
{
|
||||
return desc->physical_start + (desc->num_pages << EFI_PAGE_SHIFT);
|
||||
}
|
||||
|
||||
static void efi_mem_sort(void)
|
||||
{
|
||||
struct list_head *lhandle;
|
||||
struct efi_mem_list *prevmem = NULL;
|
||||
bool merge_again = true;
|
||||
|
||||
list_sort(NULL, &efi_mem, efi_mem_cmp);
|
||||
|
||||
/* Now merge entries that can be merged */
|
||||
while (merge_again) {
|
||||
merge_again = false;
|
||||
list_for_each(lhandle, &efi_mem) {
|
||||
struct efi_mem_list *lmem;
|
||||
struct efi_mem_desc *prev = &prevmem->desc;
|
||||
struct efi_mem_desc *cur;
|
||||
uint64_t pages;
|
||||
|
||||
lmem = list_entry(lhandle, struct efi_mem_list, link);
|
||||
if (!prevmem) {
|
||||
prevmem = lmem;
|
||||
continue;
|
||||
}
|
||||
|
||||
cur = &lmem->desc;
|
||||
|
||||
if ((desc_get_end(cur) == prev->physical_start) &&
|
||||
(prev->type == cur->type) &&
|
||||
(prev->attribute == cur->attribute)) {
|
||||
/* There is an existing map before, reuse it */
|
||||
pages = cur->num_pages;
|
||||
prev->num_pages += pages;
|
||||
prev->physical_start -= pages << EFI_PAGE_SHIFT;
|
||||
prev->virtual_start -= pages << EFI_PAGE_SHIFT;
|
||||
list_del(&lmem->link);
|
||||
free(lmem);
|
||||
|
||||
merge_again = true;
|
||||
break;
|
||||
}
|
||||
|
||||
prevmem = lmem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** efi_mem_carve_out - unmap memory region
|
||||
|
@ -303,7 +348,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
|
|||
switch (type) {
|
||||
case EFI_ALLOCATE_ANY_PAGES:
|
||||
/* Any page */
|
||||
addr = efi_find_free_memory(len, gd->start_addr_sp);
|
||||
addr = efi_find_free_memory(len, -1ULL);
|
||||
if (!addr) {
|
||||
r = EFI_NOT_FOUND;
|
||||
break;
|
||||
|
|
79
lib/efi_loader/efi_root_node.c
Normal file
79
lib/efi_loader/efi_root_node.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Root node for system services
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <efi_loader.h>
|
||||
|
||||
const efi_guid_t efi_u_boot_guid = U_BOOT_GUID;
|
||||
|
||||
struct efi_root_dp {
|
||||
struct efi_device_path_vendor vendor;
|
||||
struct efi_device_path end;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* efi_root_node_register() - create root node
|
||||
*
|
||||
* Create the root node on which we install all protocols that are
|
||||
* not related to a loaded image or a driver.
|
||||
*
|
||||
* Return: status code
|
||||
*/
|
||||
efi_status_t efi_root_node_register(void)
|
||||
{
|
||||
efi_handle_t root;
|
||||
efi_status_t ret;
|
||||
struct efi_root_dp *dp;
|
||||
|
||||
/* Create handle */
|
||||
ret = efi_create_handle(&root);
|
||||
if (ret != EFI_SUCCESS)
|
||||
return ret;
|
||||
|
||||
/* Install device path protocol */
|
||||
dp = calloc(1, sizeof(*dp));
|
||||
if (!dp)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
/* Fill vendor node */
|
||||
dp->vendor.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
|
||||
dp->vendor.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
|
||||
dp->vendor.dp.length = sizeof(struct efi_device_path_vendor);
|
||||
dp->vendor.guid = efi_u_boot_guid;
|
||||
|
||||
/* Fill end node */
|
||||
dp->end.type = DEVICE_PATH_TYPE_END;
|
||||
dp->end.sub_type = DEVICE_PATH_SUB_TYPE_END;
|
||||
dp->end.length = sizeof(struct efi_device_path);
|
||||
|
||||
/* Install device path protocol */
|
||||
ret = efi_add_protocol(root, &efi_guid_device_path, dp);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
/* Install device path to text protocol */
|
||||
ret = efi_add_protocol(root, &efi_guid_device_path_to_text_protocol,
|
||||
(void *)&efi_device_path_to_text);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
/* Install device path utilities protocol */
|
||||
ret = efi_add_protocol(root, &efi_guid_device_path_utilities_protocol,
|
||||
(void *)&efi_device_path_utilities);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
/* Install Unicode collation protocol */
|
||||
ret = efi_add_protocol(root, &efi_guid_unicode_collation_protocol,
|
||||
(void *)&efi_unicode_collation_protocol);
|
||||
if (ret != EFI_SUCCESS)
|
||||
goto failure;
|
||||
|
||||
failure:
|
||||
return ret;
|
||||
}
|
|
@ -30,8 +30,9 @@ static efi_status_t __efi_runtime EFIAPI efi_device_error(void);
|
|||
static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void);
|
||||
|
||||
/*
|
||||
* TODO(sjg@chromium.org): These defines and structs should come from the elf
|
||||
* header for each arch (or a generic header) rather than being repeated here.
|
||||
* TODO(sjg@chromium.org): These defines and structures should come from the ELF
|
||||
* header for each architecture (or a generic header) rather than being repeated
|
||||
* here.
|
||||
*/
|
||||
#if defined(__aarch64__)
|
||||
#define R_RELATIVE R_AARCH64_RELATIVE
|
||||
|
@ -79,7 +80,7 @@ struct elf_rela {
|
|||
};
|
||||
|
||||
/*
|
||||
* EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI
|
||||
* EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI
|
||||
* payload are running concurrently at the same time. In this mode, we can
|
||||
* handle a good number of runtime callbacks
|
||||
*/
|
||||
|
@ -97,7 +98,7 @@ void __efi_runtime efi_update_table_header_crc32(struct efi_table_hdr *table)
|
|||
}
|
||||
|
||||
/**
|
||||
* efi_reset_system_boottime() - reset system at boottime
|
||||
* efi_reset_system_boottime() - reset system at boot time
|
||||
*
|
||||
* This function implements the ResetSystem() runtime service before
|
||||
* SetVirtualAddressMap() is called.
|
||||
|
@ -144,7 +145,7 @@ static void EFIAPI efi_reset_system_boottime(
|
|||
}
|
||||
|
||||
/**
|
||||
* efi_get_time_boottime() - get current time at boottime
|
||||
* efi_get_time_boottime() - get current time at boot time
|
||||
*
|
||||
* This function implements the GetTime runtime service before
|
||||
* SetVirtualAddressMap() is called.
|
||||
|
@ -335,7 +336,7 @@ static void efi_runtime_detach(ulong offset)
|
|||
*p = newaddr;
|
||||
}
|
||||
|
||||
/* Update crc32 */
|
||||
/* Update CRC32 */
|
||||
efi_update_table_header_crc32(&efi_runtime_services.hdr);
|
||||
}
|
||||
|
||||
|
@ -489,7 +490,7 @@ static efi_status_t EFIAPI efi_set_virtual_address_map(
|
|||
* available at runtime.
|
||||
*
|
||||
* @mmio_ptr: address of the memory-mapped IO region
|
||||
* @len: size of thememory-mapped IO region
|
||||
* @len: size of the memory-mapped IO region
|
||||
* Returns: status code
|
||||
*/
|
||||
efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len)
|
||||
|
@ -607,7 +608,7 @@ efi_status_t __efi_runtime EFIAPI efi_update_capsule(
|
|||
*
|
||||
* @capsule_header_array: pointer to array of virtual pointers
|
||||
* @capsule_count: number of pointers in capsule_header_array
|
||||
* @capsule_size: maximum capsule size
|
||||
* @maximum_capsule_size: maximum capsule size
|
||||
* @reset_type: type of reset needed for capsule update
|
||||
* Returns: status code
|
||||
*/
|
||||
|
|
329
lib/efi_loader/efi_unicode_collation.c
Normal file
329
lib/efi_loader/efi_unicode_collation.c
Normal file
|
@ -0,0 +1,329 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* EFI Unicode collation protocol
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <charset.h>
|
||||
#include <cp1250.h>
|
||||
#include <cp437.h>
|
||||
#include <efi_loader.h>
|
||||
|
||||
/* Characters that may not be used in file names */
|
||||
static const char illegal[] = "<>:\"/\\|?*";
|
||||
|
||||
/*
|
||||
* EDK2 assumes codepage 1250 when creating FAT 8.3 file names.
|
||||
* Linux defaults to codepage 437 for FAT 8.3 file names.
|
||||
*/
|
||||
#if CONFIG_FAT_DEFAULT_CODEPAGE == 1250
|
||||
/* Unicode code points for code page 1250 characters 0x80 - 0xff */
|
||||
static const u16 codepage[] = CP1250;
|
||||
#else
|
||||
/* Unicode code points for code page 437 characters 0x80 - 0xff */
|
||||
static const u16 codepage[] = CP437;
|
||||
#endif
|
||||
|
||||
/* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */
|
||||
const efi_guid_t efi_guid_unicode_collation_protocol =
|
||||
EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
|
||||
|
||||
/**
|
||||
* efi_stri_coll() - compare utf-16 strings case-insenitively
|
||||
*
|
||||
* @this: unicode collation protocol instance
|
||||
* @s1: first string
|
||||
* @s2: second string
|
||||
*
|
||||
* This function implements the StriColl() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
*
|
||||
* See the Unified Extensible Firmware Interface (UEFI) specification for
|
||||
* details.
|
||||
*
|
||||
* TODO:
|
||||
* The implementation does not follow the Unicode collation algorithm.
|
||||
* For ASCII characters it results in the same sort order as EDK2.
|
||||
* We could use table UNICODE_CAPITALIZATION_TABLE for better results.
|
||||
*
|
||||
* Return: 0: s1 == s2, > 0: s1 > s2, < 0: s1 < s2
|
||||
*/
|
||||
static efi_intn_t EFIAPI efi_stri_coll(
|
||||
struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2)
|
||||
{
|
||||
s32 c1, c2;
|
||||
efi_intn_t ret = 0;
|
||||
|
||||
EFI_ENTRY("%p, %ls, %ls", this, s1, s2);
|
||||
for (; *s1 | *s2; ++s1, ++s2) {
|
||||
c1 = utf_to_upper(*s1);
|
||||
c2 = utf_to_upper(*s2);
|
||||
if (c1 < c2) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
} else if (c1 > c2) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* metai_match() - compare utf-16 string with a pattern string case-insenitively
|
||||
*
|
||||
* @s: string to compare
|
||||
* @p: pattern string
|
||||
*
|
||||
* The pattern string may use these:
|
||||
* - * matches >= 0 characters
|
||||
* - ? matches 1 character
|
||||
* - [<char1><char2>...<charN>] match any character in the set
|
||||
* - [<char1>-<char2>] matches any character in the range
|
||||
*
|
||||
* This function is called my efi_metai_match().
|
||||
*
|
||||
* For '*' pattern searches this function calls itself recursively.
|
||||
* Performance-wise this is suboptimal, especially for multiple '*' wildcards.
|
||||
* But it results in simple code.
|
||||
*
|
||||
* Return: true if the string is matched.
|
||||
*/
|
||||
static bool metai_match(const u16 *s, const u16 *p)
|
||||
{
|
||||
u16 first;
|
||||
|
||||
for (; *s && *p; ++s, ++p) {
|
||||
switch (*p) {
|
||||
case '*':
|
||||
/* Match 0 or more characters */
|
||||
++p;
|
||||
for (;; ++s) {
|
||||
if (metai_match(s, p))
|
||||
return true;
|
||||
if (!*s)
|
||||
return false;
|
||||
}
|
||||
case '?':
|
||||
/* Match any one character */
|
||||
break;
|
||||
case '[':
|
||||
/* Match any character in the set */
|
||||
++p;
|
||||
first = *p;
|
||||
if (first == ']')
|
||||
/* Empty set */
|
||||
return false;
|
||||
++p;
|
||||
if (*p == '-') {
|
||||
/* Range */
|
||||
++p;
|
||||
if (*s < first || *s > *p)
|
||||
return false;
|
||||
++p;
|
||||
if (*p != ']')
|
||||
return false;
|
||||
} else {
|
||||
/* Set */
|
||||
bool hit = false;
|
||||
|
||||
if (*s == first)
|
||||
hit = true;
|
||||
for (; *p && *p != ']'; ++p) {
|
||||
if (*p == *s)
|
||||
hit = true;
|
||||
}
|
||||
if (!hit || *p != ']')
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Match one character */
|
||||
if (*p != *s)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!*p && !*s)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_metai_match() - compare utf-16 string with a pattern string
|
||||
* case-insenitively
|
||||
*
|
||||
* @this: unicode collation protocol instance
|
||||
* @s: string to compare
|
||||
* @p: pattern string
|
||||
*
|
||||
* The pattern string may use these:
|
||||
* - * matches >= 0 characters
|
||||
* - ? matches 1 character
|
||||
* - [<char1><char2>...<charN>] match any character in the set
|
||||
* - [<char1>-<char2>] matches any character in the range
|
||||
*
|
||||
* This function implements the MetaMatch() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
*
|
||||
* Return: true if the string is matched.
|
||||
*/
|
||||
static bool EFIAPI efi_metai_match(struct efi_unicode_collation_protocol *this,
|
||||
const u16 *string, const u16 *pattern)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
EFI_ENTRY("%p, %ls, %ls", this, string, pattern);
|
||||
ret = metai_match(string, pattern);
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_str_lwr() - convert to lower case
|
||||
*
|
||||
* @this: unicode collation protocol instance
|
||||
* @string: string to convert
|
||||
* @p: pattern string
|
||||
*
|
||||
* The conversion is done in place. As long as upper and lower letters use the
|
||||
* same number of words this does not pose a problem.
|
||||
*
|
||||
* This function implements the StrLwr() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
*/
|
||||
static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this,
|
||||
u16 *string)
|
||||
{
|
||||
EFI_ENTRY("%p, %ls", this, string);
|
||||
for (; *string; ++string)
|
||||
*string = utf_to_lower(*string);
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_str_upr() - convert to upper case
|
||||
*
|
||||
* @this: unicode collation protocol instance
|
||||
* @string: string to convert
|
||||
* @p: pattern string
|
||||
*
|
||||
* The conversion is done in place. As long as upper and lower letters use the
|
||||
* same number of words this does not pose a problem.
|
||||
*
|
||||
* This function implements the StrUpr() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
*/
|
||||
static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this,
|
||||
u16 *string)
|
||||
{
|
||||
EFI_ENTRY("%p, %ls", this, string);
|
||||
for (; *string; ++string)
|
||||
*string = utf_to_upper(*string);
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_fat_to_str() - convert an 8.3 file name from an OEM codepage to Unicode
|
||||
*
|
||||
* @this: unicode collation protocol instance
|
||||
* @fat_size: size of the string to convert
|
||||
* @fat: string to convert
|
||||
* @string: converted string
|
||||
*
|
||||
* This function implements the FatToStr() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
*/
|
||||
static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this,
|
||||
efi_uintn_t fat_size, char *fat, u16 *string)
|
||||
{
|
||||
efi_uintn_t i;
|
||||
u16 c;
|
||||
|
||||
EFI_ENTRY("%p, %zu, %s, %p", this, fat_size, fat, string);
|
||||
for (i = 0; i < fat_size; ++i) {
|
||||
c = (unsigned char)fat[i];
|
||||
if (c > 0x80)
|
||||
c = codepage[i - 0x80];
|
||||
string[i] = c;
|
||||
if (!c)
|
||||
break;
|
||||
}
|
||||
string[i] = 0;
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_fat_to_str() - convert a utf-16 string to legal characters for a FAT
|
||||
* file name in an OEM code page
|
||||
*
|
||||
* @this: unicode collation protocol instance
|
||||
* @string: Unicode string to convert
|
||||
* @fat_size: size of the target buffer
|
||||
* @fat: converted string
|
||||
*
|
||||
* This function implements the StrToFat() service of the
|
||||
* EFI_UNICODE_COLLATION_PROTOCOL.
|
||||
*
|
||||
* Return: true if an illegal character was substituted by '_'.
|
||||
*/
|
||||
static bool EFIAPI efi_str_to_fat(struct efi_unicode_collation_protocol *this,
|
||||
const u16 *string, efi_uintn_t fat_size,
|
||||
char *fat)
|
||||
{
|
||||
efi_uintn_t i;
|
||||
s32 c;
|
||||
bool ret = false;
|
||||
|
||||
EFI_ENTRY("%p, %ls, %zu, %p", this, string, fat_size, fat);
|
||||
for (i = 0; i < fat_size;) {
|
||||
c = utf16_get(&string);
|
||||
switch (c) {
|
||||
/* Ignore period and space */
|
||||
case '.':
|
||||
case ' ':
|
||||
continue;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
c = utf_to_upper(c);
|
||||
if (c >= 0x80) {
|
||||
int j;
|
||||
|
||||
/* Look for codepage translation */
|
||||
for (j = 0; j < 0x80; ++j) {
|
||||
if (c == codepage[j]) {
|
||||
c = j + 0x80;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= 0x80) {
|
||||
c = '_';
|
||||
ret = true;
|
||||
}
|
||||
} else if (c && (c < 0x20 || strchr(illegal, c))) {
|
||||
c = '_';
|
||||
ret = true;
|
||||
}
|
||||
|
||||
fat[i] = c;
|
||||
if (!c)
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
EFI_EXIT(EFI_SUCCESS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct efi_unicode_collation_protocol efi_unicode_collation_protocol = {
|
||||
.stri_coll = efi_stri_coll,
|
||||
.metai_match = efi_metai_match,
|
||||
.str_lwr = efi_str_lwr,
|
||||
.str_upr = efi_str_upr,
|
||||
.fat_to_str = efi_fat_to_str,
|
||||
.str_to_fat = efi_str_to_fat,
|
||||
.supported_languages = "en",
|
||||
};
|
|
@ -44,10 +44,7 @@
|
|||
* converted to utf16?
|
||||
*/
|
||||
|
||||
#define MAX_VAR_NAME 31
|
||||
#define MAX_NATIVE_VAR_NAME \
|
||||
(strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \
|
||||
(MAX_VAR_NAME * MAX_UTF8_PER_UTF16))
|
||||
#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_"))
|
||||
|
||||
static int hex(int ch)
|
||||
{
|
||||
|
@ -101,18 +98,20 @@ static char *mem2hex(char *hexstr, const u8 *mem, int count)
|
|||
return hexstr;
|
||||
}
|
||||
|
||||
static efi_status_t efi_to_native(char *native, u16 *variable_name,
|
||||
static efi_status_t efi_to_native(char **native, const u16 *variable_name,
|
||||
efi_guid_t *vendor)
|
||||
{
|
||||
size_t len;
|
||||
char *pos;
|
||||
|
||||
len = utf16_strlen((u16 *)variable_name);
|
||||
if (len >= MAX_VAR_NAME)
|
||||
return EFI_DEVICE_ERROR;
|
||||
len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
|
||||
*native = malloc(len);
|
||||
if (!*native)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
native += sprintf(native, "efi_%pUl_", vendor);
|
||||
native = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
|
||||
*native = '\0';
|
||||
pos = *native;
|
||||
pos += sprintf(pos, "efi_%pUl_", vendor);
|
||||
utf16_utf8_strcpy(&pos, variable_name);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
@ -168,7 +167,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor,
|
|||
u32 *attributes, efi_uintn_t *data_size,
|
||||
void *data)
|
||||
{
|
||||
char native_name[MAX_NATIVE_VAR_NAME + 1];
|
||||
char *native_name;
|
||||
efi_status_t ret;
|
||||
unsigned long in_size;
|
||||
const char *val, *s;
|
||||
|
@ -180,13 +179,14 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, efi_guid_t *vendor,
|
|||
if (!variable_name || !vendor || !data_size)
|
||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||
|
||||
ret = efi_to_native(native_name, variable_name, vendor);
|
||||
ret = efi_to_native(&native_name, variable_name, vendor);
|
||||
if (ret)
|
||||
return EFI_EXIT(ret);
|
||||
|
||||
debug("%s: get '%s'\n", __func__, native_name);
|
||||
|
||||
val = env_get(native_name);
|
||||
free(native_name);
|
||||
if (!val)
|
||||
return EFI_EXIT(EFI_NOT_FOUND);
|
||||
|
||||
|
@ -256,35 +256,41 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
|
|||
u32 attributes, efi_uintn_t data_size,
|
||||
void *data)
|
||||
{
|
||||
char native_name[MAX_NATIVE_VAR_NAME + 1];
|
||||
char *native_name = NULL, *val = NULL, *s;
|
||||
efi_status_t ret = EFI_SUCCESS;
|
||||
char *val, *s;
|
||||
u32 attr;
|
||||
|
||||
EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
|
||||
data_size, data);
|
||||
|
||||
if (!variable_name || !vendor)
|
||||
return EFI_EXIT(EFI_INVALID_PARAMETER);
|
||||
if (!variable_name || !vendor) {
|
||||
ret = EFI_INVALID_PARAMETER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = efi_to_native(native_name, variable_name, vendor);
|
||||
ret = efi_to_native(&native_name, variable_name, vendor);
|
||||
if (ret)
|
||||
return EFI_EXIT(ret);
|
||||
goto out;
|
||||
|
||||
#define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)
|
||||
|
||||
if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
|
||||
/* delete the variable: */
|
||||
env_set(native_name, NULL);
|
||||
return EFI_EXIT(EFI_SUCCESS);
|
||||
ret = EFI_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
val = env_get(native_name);
|
||||
if (val) {
|
||||
parse_attr(val, &attr);
|
||||
|
||||
if (attr & READ_ONLY)
|
||||
return EFI_EXIT(EFI_WRITE_PROTECTED);
|
||||
if (attr & READ_ONLY) {
|
||||
/* We should not free val */
|
||||
val = NULL;
|
||||
ret = EFI_WRITE_PROTECTED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1);
|
||||
|
@ -320,6 +326,8 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor,
|
|||
if (env_set(native_name, val))
|
||||
ret = EFI_DEVICE_ERROR;
|
||||
|
||||
out:
|
||||
free(native_name);
|
||||
free(val);
|
||||
|
||||
return EFI_EXIT(ret);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config CMD_BOOTEFI_SELFTEST
|
||||
bool "Allow booting an EFI efi_selftest"
|
||||
depends on CMD_BOOTEFI
|
||||
depends on CMD_BOOTEFI && !SANDBOX
|
||||
imply FAT
|
||||
imply FAT_WRITE
|
||||
help
|
||||
|
|
|
@ -24,12 +24,15 @@ efi_selftest_event_groups.o \
|
|||
efi_selftest_exitbootservices.o \
|
||||
efi_selftest_fdt.o \
|
||||
efi_selftest_gop.o \
|
||||
efi_selftest_loaded_image.o \
|
||||
efi_selftest_manageprotocols.o \
|
||||
efi_selftest_rtc.o \
|
||||
efi_selftest_snp.o \
|
||||
efi_selftest_textinput.o \
|
||||
efi_selftest_textinputex.o \
|
||||
efi_selftest_textoutput.o \
|
||||
efi_selftest_tpl.o \
|
||||
efi_selftest_unicode_collation.o \
|
||||
efi_selftest_util.o \
|
||||
efi_selftest_variables.o \
|
||||
efi_selftest_watchdog.o
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <vsprintf.h>
|
||||
|
||||
struct efi_simple_text_output_protocol *con_out;
|
||||
struct efi_simple_input_interface *con_in;
|
||||
struct efi_simple_text_input_protocol *con_in;
|
||||
|
||||
/*
|
||||
* Print a MAC address to an u16 string
|
||||
|
|
108
lib/efi_selftest/efi_selftest_loaded_image.c
Normal file
108
lib/efi_selftest/efi_selftest_loaded_image.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* efi_selftest_loaded_image
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*
|
||||
* This unit test checks the Loaded Image Protocol.
|
||||
*/
|
||||
|
||||
#include <efi_selftest.h>
|
||||
|
||||
static efi_guid_t loaded_image_protocol_guid =
|
||||
EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2,
|
||||
0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b);
|
||||
static struct efi_boot_services *boottime;
|
||||
efi_handle_t image_handle;
|
||||
|
||||
/*
|
||||
* Setup unit test.
|
||||
*
|
||||
* @handle: handle of the loaded image
|
||||
* @systable: system table
|
||||
*/
|
||||
static int setup(const efi_handle_t img_handle,
|
||||
const struct efi_system_table *systable)
|
||||
{
|
||||
boottime = systable->boottime;
|
||||
image_handle = img_handle;
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute unit test.
|
||||
*
|
||||
* Verify that the loaded image protocol is installed on the image handle.
|
||||
* Verify that the loaded image protocol points to the system table.
|
||||
*/
|
||||
static int execute(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
efi_uintn_t i, protocol_buffer_count = 0;
|
||||
efi_guid_t **protocol_buffer = NULL;
|
||||
bool found = false;
|
||||
struct efi_loaded_image *loaded_image_protocol;
|
||||
|
||||
/*
|
||||
* Get the GUIDs of all protocols installed on the handle.
|
||||
*/
|
||||
ret = boottime->protocols_per_handle(image_handle, &protocol_buffer,
|
||||
&protocol_buffer_count);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("ProtocolsPerHandle failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
if (!protocol_buffer_count | !protocol_buffer) {
|
||||
efi_st_error("ProtocolsPerHandle returned no protocol\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
efi_st_printf("%u protocols installed on image handle\n",
|
||||
(unsigned int)protocol_buffer_count);
|
||||
for (i = 0; i < protocol_buffer_count; ++i) {
|
||||
if (efi_st_memcmp(protocol_buffer[i],
|
||||
&loaded_image_protocol_guid,
|
||||
sizeof(efi_guid_t)))
|
||||
found = true;
|
||||
}
|
||||
if (!found) {
|
||||
efi_st_printf("LoadedImageProtocol not found\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = boottime->free_pool(protocol_buffer);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("FreePool failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the loaded image protocol.
|
||||
*/
|
||||
ret = boottime->open_protocol(image_handle, &loaded_image_protocol_guid,
|
||||
(void **)&loaded_image_protocol, NULL,
|
||||
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("OpenProtocol failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
if (loaded_image_protocol->revision !=
|
||||
EFI_LOADED_IMAGE_PROTOCOL_REVISION) {
|
||||
efi_st_printf("Incorrect revision\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
if (!loaded_image_protocol->system_table ||
|
||||
loaded_image_protocol->system_table->hdr.signature !=
|
||||
EFI_SYSTEM_TABLE_SIGNATURE) {
|
||||
efi_st_printf("System table reference missing\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_UNIT_TEST(loadedimage) = {
|
||||
.name = "loaded image",
|
||||
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
};
|
|
@ -179,7 +179,12 @@ static int execute(void)
|
|||
efi_st_error("LocateHandleBuffer failed to locate new handle\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
|
||||
/* Release buffer */
|
||||
ret = boottime->free_pool(buffer);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("FreePool failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test error handling in UninstallMultipleProtocols
|
||||
|
@ -221,6 +226,7 @@ static int execute(void)
|
|||
efi_st_error("LocateHandleBuffer failed to locate new handle\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
/* Clear the buffer, we are reusing it it the next step. */
|
||||
boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
|
||||
|
||||
/*
|
||||
|
@ -248,7 +254,12 @@ static int execute(void)
|
|||
efi_st_error("LocateHandle failed to locate new handles\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
|
||||
/* Release buffer */
|
||||
ret = boottime->free_pool(buffer);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("FreePool failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test LocateProtocol
|
||||
|
@ -319,6 +330,12 @@ static int execute(void)
|
|||
efi_st_error("Failed to get protocols per handle\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
/* Release buffer */
|
||||
ret = boottime->free_pool(prot_buffer);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("FreePool failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Uninstall remaining protocols
|
||||
|
|
|
@ -14,113 +14,8 @@
|
|||
|
||||
#include <efi_selftest.h>
|
||||
|
||||
struct translate {
|
||||
u16 code;
|
||||
u16 *text;
|
||||
};
|
||||
|
||||
static struct efi_boot_services *boottime;
|
||||
|
||||
static struct translate control_characters[] = {
|
||||
{0, L"Null"},
|
||||
{8, L"BS"},
|
||||
{9, L"TAB"},
|
||||
{10, L"LF"},
|
||||
{13, L"CR"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
static u16 ch[] = L"' '";
|
||||
static u16 unknown[] = L"unknown";
|
||||
|
||||
static struct translate scan_codes[] = {
|
||||
{0x00, L"Null"},
|
||||
{0x01, L"Up"},
|
||||
{0x02, L"Down"},
|
||||
{0x03, L"Right"},
|
||||
{0x04, L"Left"},
|
||||
{0x05, L"Home"},
|
||||
{0x06, L"End"},
|
||||
{0x07, L"Insert"},
|
||||
{0x08, L"Delete"},
|
||||
{0x09, L"Page Up"},
|
||||
{0x0a, L"Page Down"},
|
||||
{0x0b, L"FN 1"},
|
||||
{0x0c, L"FN 2"},
|
||||
{0x0d, L"FN 3"},
|
||||
{0x0e, L"FN 4"},
|
||||
{0x0f, L"FN 5"},
|
||||
{0x10, L"FN 6"},
|
||||
{0x11, L"FN 7"},
|
||||
{0x12, L"FN 8"},
|
||||
{0x13, L"FN 9"},
|
||||
{0x14, L"FN 10"},
|
||||
{0x15, L"FN 11"},
|
||||
{0x16, L"FN 12"},
|
||||
{0x17, L"Escape"},
|
||||
{0x68, L"FN 13"},
|
||||
{0x69, L"FN 14"},
|
||||
{0x6a, L"FN 15"},
|
||||
{0x6b, L"FN 16"},
|
||||
{0x6c, L"FN 17"},
|
||||
{0x6d, L"FN 18"},
|
||||
{0x6e, L"FN 19"},
|
||||
{0x6f, L"FN 20"},
|
||||
{0x70, L"FN 21"},
|
||||
{0x71, L"FN 22"},
|
||||
{0x72, L"FN 23"},
|
||||
{0x73, L"FN 24"},
|
||||
{0x7f, L"Mute"},
|
||||
{0x80, L"Volume Up"},
|
||||
{0x81, L"Volume Down"},
|
||||
{0x100, L"Brightness Up"},
|
||||
{0x101, L"Brightness Down"},
|
||||
{0x102, L"Suspend"},
|
||||
{0x103, L"Hibernate"},
|
||||
{0x104, L"Toggle Display"},
|
||||
{0x105, L"Recovery"},
|
||||
{0x106, L"Reject"},
|
||||
{0x0, NULL},
|
||||
};
|
||||
|
||||
/*
|
||||
* Translate a unicode character to a string.
|
||||
*
|
||||
* @code unicode character
|
||||
* @return string
|
||||
*/
|
||||
static u16 *translate_char(u16 code)
|
||||
{
|
||||
struct translate *tr;
|
||||
|
||||
if (code >= ' ') {
|
||||
ch[1] = code;
|
||||
return ch;
|
||||
}
|
||||
for (tr = control_characters; tr->text; ++tr) {
|
||||
if (tr->code == code)
|
||||
return tr->text;
|
||||
}
|
||||
return unknown;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a scan code to a human readable string.
|
||||
*
|
||||
* @code unicode character
|
||||
* @return string
|
||||
*/
|
||||
static u16 *translate_code(u16 code)
|
||||
{
|
||||
struct translate *tr;
|
||||
|
||||
for (tr = scan_codes; tr->text; ++tr) {
|
||||
if (tr->code == code)
|
||||
return tr->text;
|
||||
}
|
||||
return unknown;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup unit test.
|
||||
*
|
||||
|
@ -145,24 +40,45 @@ static int execute(void)
|
|||
{
|
||||
struct efi_input_key input_key = {0};
|
||||
efi_status_t ret;
|
||||
efi_uintn_t index;
|
||||
|
||||
/* Drain the console input */
|
||||
ret = con_in->reset(con_in, true);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("Reset failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = con_in->read_key_stroke(con_in, &input_key);
|
||||
if (ret != EFI_NOT_READY) {
|
||||
efi_st_error("Empty buffer not reported\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
efi_st_printf("Waiting for your input\n");
|
||||
efi_st_printf("To terminate type 'x'\n");
|
||||
|
||||
for (;;) {
|
||||
/* Wait for next key */
|
||||
do {
|
||||
ret = con_in->read_key_stroke(con_in, &input_key);
|
||||
} while (ret == EFI_NOT_READY);
|
||||
ret = boottime->wait_for_event(1, &con_in->wait_for_key,
|
||||
&index);
|
||||
if (ret != EFI_ST_SUCCESS) {
|
||||
efi_st_error("WaitForEvent failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = con_in->read_key_stroke(con_in, &input_key);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("ReadKeyStroke failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/* Allow 5 minutes until time out */
|
||||
boottime->set_watchdog_timer(300, 0, 0, NULL);
|
||||
|
||||
efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n",
|
||||
(unsigned int)input_key.unicode_char,
|
||||
translate_char(input_key.unicode_char),
|
||||
efi_st_translate_char(input_key.unicode_char),
|
||||
(unsigned int)input_key.scan_code,
|
||||
translate_code(input_key.scan_code));
|
||||
efi_st_translate_code(input_key.scan_code));
|
||||
|
||||
switch (input_key.unicode_char) {
|
||||
case 'x':
|
||||
|
|
198
lib/efi_selftest/efi_selftest_textinputex.c
Normal file
198
lib/efi_selftest/efi_selftest_textinputex.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* efi_selftest_textinput
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*
|
||||
* Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
|
||||
* The unicode character and the scan code are printed for text
|
||||
* input. To run the test:
|
||||
*
|
||||
* setenv efi_selftest extended text input
|
||||
* bootefi selftest
|
||||
*/
|
||||
|
||||
#include <efi_selftest.h>
|
||||
|
||||
static const efi_guid_t text_input_ex_protocol_guid =
|
||||
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
|
||||
|
||||
static struct efi_simple_text_input_ex_protocol *con_in_ex;
|
||||
|
||||
static struct efi_boot_services *boottime;
|
||||
|
||||
static void *efi_key_notify_handle;
|
||||
static bool efi_running;
|
||||
|
||||
/**
|
||||
* efi_key_notify_function() - key notification function
|
||||
*
|
||||
* This function is called when the registered key is hit.
|
||||
*
|
||||
* @key_data: next key
|
||||
* Return: status code
|
||||
*/
|
||||
static efi_status_t EFIAPI efi_key_notify_function
|
||||
(struct efi_key_data *key_data)
|
||||
{
|
||||
efi_running = false;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup unit test.
|
||||
*
|
||||
* @handle: handle of the loaded image
|
||||
* @systable: system table
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int setup(const efi_handle_t handle,
|
||||
const struct efi_system_table *systable)
|
||||
{
|
||||
efi_status_t ret;
|
||||
struct efi_key_data key_data = {
|
||||
.key = {
|
||||
.scan_code = 0,
|
||||
.unicode_char = 0x18
|
||||
},
|
||||
.key_state = {
|
||||
.key_shift_state = EFI_SHIFT_STATE_VALID |
|
||||
EFI_LEFT_CONTROL_PRESSED,
|
||||
.key_toggle_state = EFI_TOGGLE_STATE_INVALID,
|
||||
},
|
||||
};
|
||||
|
||||
boottime = systable->boottime;
|
||||
|
||||
ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL,
|
||||
(void **)&con_in_ex);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
con_in_ex = NULL;
|
||||
efi_st_error
|
||||
("Extended text input protocol is not available.\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = con_in_ex->register_key_notify(con_in_ex, &key_data,
|
||||
efi_key_notify_function,
|
||||
&efi_key_notify_handle);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_key_notify_handle = NULL;
|
||||
efi_st_error
|
||||
("Notify function could not be registered.\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
efi_running = true;
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tear down unit test.
|
||||
*
|
||||
* Unregister notify function.
|
||||
*
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int teardown(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
ret = con_in_ex->unregister_key_notify
|
||||
(con_in_ex, efi_key_notify_handle);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error
|
||||
("Notify function could not be registered.\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
/*
|
||||
* Execute unit test.
|
||||
*
|
||||
* @return: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int execute(void)
|
||||
{
|
||||
struct efi_key_data input_key = { {0, 0}, {0, 0} };
|
||||
efi_status_t ret;
|
||||
efi_uintn_t index;
|
||||
|
||||
if (!con_in_ex) {
|
||||
efi_st_printf("Setup failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/* Drain the console input */
|
||||
ret = con_in_ex->reset(con_in_ex, true);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("Reset failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
|
||||
if (ret != EFI_NOT_READY) {
|
||||
efi_st_error("Empty buffer not reported\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
efi_st_printf("Waiting for your input\n");
|
||||
efi_st_printf("To terminate type 'CTRL+x'\n");
|
||||
|
||||
while (efi_running) {
|
||||
/* Wait for next key */
|
||||
ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex,
|
||||
&index);
|
||||
if (ret != EFI_ST_SUCCESS) {
|
||||
efi_st_error("WaitForEvent failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("ReadKeyStroke failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
/* Allow 5 minutes until time out */
|
||||
boottime->set_watchdog_timer(300, 0, 0, NULL);
|
||||
|
||||
efi_st_printf("Unicode char %u (%ps), scan code %u (",
|
||||
(unsigned int)input_key.key.unicode_char,
|
||||
efi_st_translate_char(input_key.key.unicode_char),
|
||||
(unsigned int)input_key.key.scan_code);
|
||||
if (input_key.key_state.key_shift_state &
|
||||
EFI_SHIFT_STATE_VALID) {
|
||||
if (input_key.key_state.key_shift_state &
|
||||
(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED))
|
||||
efi_st_printf("SHIFT+");
|
||||
if (input_key.key_state.key_shift_state &
|
||||
(EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED))
|
||||
efi_st_printf("ALT+");
|
||||
if (input_key.key_state.key_shift_state &
|
||||
(EFI_LEFT_CONTROL_PRESSED |
|
||||
EFI_RIGHT_CONTROL_PRESSED))
|
||||
efi_st_printf("CTRL+");
|
||||
if (input_key.key_state.key_shift_state &
|
||||
(EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED))
|
||||
efi_st_printf("META+");
|
||||
if (input_key.key_state.key_shift_state ==
|
||||
EFI_SHIFT_STATE_VALID)
|
||||
efi_st_printf("+");
|
||||
}
|
||||
|
||||
efi_st_printf("%ps)\n",
|
||||
efi_st_translate_code(input_key.key.scan_code));
|
||||
|
||||
}
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_UNIT_TEST(textinputex) = {
|
||||
.name = "extended text input",
|
||||
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
||||
.setup = setup,
|
||||
.execute = execute,
|
||||
.teardown = teardown,
|
||||
.on_request = true,
|
||||
};
|
260
lib/efi_selftest/efi_selftest_unicode_collation.c
Normal file
260
lib/efi_selftest/efi_selftest_unicode_collation.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* efi_selftest_unicode_collation
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*
|
||||
* Test unicode collation protocol.
|
||||
*/
|
||||
|
||||
#include <efi_selftest.h>
|
||||
|
||||
static const efi_guid_t unicode_collation_protocol_guid =
|
||||
EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
|
||||
|
||||
static struct efi_boot_services *boottime;
|
||||
|
||||
static struct efi_unicode_collation_protocol *unicode_collation_protocol;
|
||||
|
||||
/**
|
||||
* setup() - setup unit test.
|
||||
*
|
||||
* @handle: handle of the loaded image
|
||||
* @systable: system table
|
||||
* ReturnValue: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int setup(const efi_handle_t handle,
|
||||
const struct efi_system_table *systable)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
boottime = systable->boottime;
|
||||
|
||||
ret = boottime->locate_protocol(&unicode_collation_protocol_guid, NULL,
|
||||
(void **)&unicode_collation_protocol);
|
||||
if (ret != EFI_SUCCESS) {
|
||||
unicode_collation_protocol = NULL;
|
||||
efi_st_error("Unicode collation protocol is not available.\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_stri_coll(void)
|
||||
{
|
||||
efi_intn_t ret;
|
||||
u16 c1[] = L"first";
|
||||
u16 c2[] = L"FIRST";
|
||||
u16 c3[] = L"second";
|
||||
|
||||
ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol,
|
||||
c1, c2);
|
||||
if (ret) {
|
||||
efi_st_error(
|
||||
"stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c2, ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol,
|
||||
c1, c3);
|
||||
if (ret >= 0) {
|
||||
efi_st_error(
|
||||
"stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c3, ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol,
|
||||
c3, c1);
|
||||
if (ret <= 0) {
|
||||
efi_st_error(
|
||||
"stri_coll(\"%ps\", \"%ps\") = %zu\n", c3, c1, ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_metai_match(void)
|
||||
{
|
||||
bool ret;
|
||||
const u16 c[] = L"Das U-Boot";
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"*");
|
||||
if (!ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"Da[rstu] U-Boot");
|
||||
if (!ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"Da[q-v] U-Boot");
|
||||
if (!ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"Da? U-Boot");
|
||||
if (!ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"D*Bo*t");
|
||||
if (!ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"Da[xyz] U-Boot");
|
||||
if (ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"Da[a-d] U-Boot");
|
||||
if (ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"Da?? U-Boot");
|
||||
if (ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = unicode_collation_protocol->metai_match(
|
||||
unicode_collation_protocol, c, L"D*Bo*tt");
|
||||
if (ret) {
|
||||
efi_st_error("metai_match returned %u\n", ret);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_str_lwr(void)
|
||||
{
|
||||
u16 c[] = L"U-Boot";
|
||||
|
||||
unicode_collation_protocol->str_lwr(unicode_collation_protocol, c);
|
||||
if (efi_st_strcmp_16_8(c, "u-boot")) {
|
||||
efi_st_error("str_lwr returned \"%ps\"\n", c);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_str_upr(void)
|
||||
{
|
||||
u16 c[] = L"U-Boot";
|
||||
|
||||
unicode_collation_protocol->str_upr(unicode_collation_protocol, c);
|
||||
if (efi_st_strcmp_16_8(c, "U-BOOT")) {
|
||||
efi_st_error("str_lwr returned \"%ps\"\n", c);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_fat_to_str(void)
|
||||
{
|
||||
u16 str[16];
|
||||
|
||||
boottime->set_mem(str, sizeof(str), 0);
|
||||
unicode_collation_protocol->fat_to_str(unicode_collation_protocol, 6,
|
||||
"U-BOOT", str);
|
||||
if (efi_st_strcmp_16_8(str, "U-BOOT")) {
|
||||
efi_st_error("fat_to_str returned \"%ps\"\n", str);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
static int test_str_to_fat(void)
|
||||
{
|
||||
char fat[16];
|
||||
bool ret;
|
||||
|
||||
boottime->set_mem(fat, sizeof(fat), 0);
|
||||
ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol,
|
||||
L"U -Boo.t", 6, fat);
|
||||
if (ret || efi_st_strcmp_16_8(L"U-BOOT", fat)) {
|
||||
efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
boottime->set_mem(fat, 16, 0);
|
||||
ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol,
|
||||
L"U\\Boot", 6, fat);
|
||||
if (!ret || efi_st_strcmp_16_8(L"U_BOOT", fat)) {
|
||||
efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat);
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* execute() - Execute unit test.
|
||||
*
|
||||
* ReturnValue: EFI_ST_SUCCESS for success
|
||||
*/
|
||||
static int execute(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!unicode_collation_protocol) {
|
||||
efi_st_printf("Unicode collation protocol missing\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
|
||||
ret = test_stri_coll();
|
||||
if (ret != EFI_ST_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = test_metai_match();
|
||||
if (ret != EFI_ST_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = test_str_lwr();
|
||||
if (ret != EFI_ST_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = test_str_upr();
|
||||
if (ret != EFI_ST_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = test_fat_to_str();
|
||||
if (ret != EFI_ST_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = test_str_to_fat();
|
||||
if (ret != EFI_ST_SUCCESS)
|
||||
return ret;
|
||||
|
||||
return EFI_ST_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_UNIT_TEST(unicoll) = {
|
||||
.name = "unicode collation",
|
||||
.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
|
||||
.execute = execute,
|
||||
.setup = setup,
|
||||
};
|
|
@ -9,6 +9,99 @@
|
|||
|
||||
#include <efi_selftest.h>
|
||||
|
||||
struct efi_st_translate {
|
||||
u16 code;
|
||||
u16 *text;
|
||||
};
|
||||
|
||||
static struct efi_st_translate efi_st_control_characters[] = {
|
||||
{0, L"Null"},
|
||||
{8, L"BS"},
|
||||
{9, L"TAB"},
|
||||
{10, L"LF"},
|
||||
{13, L"CR"},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
static u16 efi_st_ch[] = L"' '";
|
||||
static u16 efi_st_unknown[] = L"unknown";
|
||||
|
||||
static struct efi_st_translate efi_st_scan_codes[] = {
|
||||
{0x00, L"Null"},
|
||||
{0x01, L"Up"},
|
||||
{0x02, L"Down"},
|
||||
{0x03, L"Right"},
|
||||
{0x04, L"Left"},
|
||||
{0x05, L"Home"},
|
||||
{0x06, L"End"},
|
||||
{0x07, L"Insert"},
|
||||
{0x08, L"Delete"},
|
||||
{0x09, L"Page Up"},
|
||||
{0x0a, L"Page Down"},
|
||||
{0x0b, L"FN 1"},
|
||||
{0x0c, L"FN 2"},
|
||||
{0x0d, L"FN 3"},
|
||||
{0x0e, L"FN 4"},
|
||||
{0x0f, L"FN 5"},
|
||||
{0x10, L"FN 6"},
|
||||
{0x11, L"FN 7"},
|
||||
{0x12, L"FN 8"},
|
||||
{0x13, L"FN 9"},
|
||||
{0x14, L"FN 10"},
|
||||
{0x15, L"FN 11"},
|
||||
{0x16, L"FN 12"},
|
||||
{0x17, L"Escape"},
|
||||
{0x68, L"FN 13"},
|
||||
{0x69, L"FN 14"},
|
||||
{0x6a, L"FN 15"},
|
||||
{0x6b, L"FN 16"},
|
||||
{0x6c, L"FN 17"},
|
||||
{0x6d, L"FN 18"},
|
||||
{0x6e, L"FN 19"},
|
||||
{0x6f, L"FN 20"},
|
||||
{0x70, L"FN 21"},
|
||||
{0x71, L"FN 22"},
|
||||
{0x72, L"FN 23"},
|
||||
{0x73, L"FN 24"},
|
||||
{0x7f, L"Mute"},
|
||||
{0x80, L"Volume Up"},
|
||||
{0x81, L"Volume Down"},
|
||||
{0x100, L"Brightness Up"},
|
||||
{0x101, L"Brightness Down"},
|
||||
{0x102, L"Suspend"},
|
||||
{0x103, L"Hibernate"},
|
||||
{0x104, L"Toggle Display"},
|
||||
{0x105, L"Recovery"},
|
||||
{0x106, L"Reject"},
|
||||
{0x0, NULL},
|
||||
};
|
||||
|
||||
u16 *efi_st_translate_char(u16 code)
|
||||
{
|
||||
struct efi_st_translate *tr;
|
||||
|
||||
if (code >= ' ') {
|
||||
efi_st_ch[1] = code;
|
||||
return efi_st_ch;
|
||||
}
|
||||
for (tr = efi_st_control_characters; tr->text; ++tr) {
|
||||
if (tr->code == code)
|
||||
return tr->text;
|
||||
}
|
||||
return efi_st_unknown;
|
||||
}
|
||||
|
||||
u16 *efi_st_translate_code(u16 code)
|
||||
{
|
||||
struct efi_st_translate *tr;
|
||||
|
||||
for (tr = efi_st_scan_codes; tr->text; ++tr) {
|
||||
if (tr->code == code)
|
||||
return tr->text;
|
||||
}
|
||||
return efi_st_unknown;
|
||||
}
|
||||
|
||||
int efi_st_memcmp(const void *buf1, const void *buf2, size_t length)
|
||||
{
|
||||
const u8 *pos1 = buf1;
|
||||
|
|
|
@ -274,28 +274,23 @@ static char *string(char *buf, char *end, char *s, int field_width,
|
|||
return buf;
|
||||
}
|
||||
|
||||
/* U-Boot uses UTF-16 strings in the EFI context only. */
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
static char *string16(char *buf, char *end, u16 *s, int field_width,
|
||||
int precision, int flags)
|
||||
{
|
||||
u16 *str = s ? s : L"<NULL>";
|
||||
int utf16_len = utf16_strnlen(str, precision);
|
||||
u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
|
||||
int utf8_len, i;
|
||||
|
||||
utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
|
||||
ssize_t len = utf16_strnlen(str, precision);
|
||||
|
||||
if (!(flags & LEFT))
|
||||
while (utf8_len < field_width--)
|
||||
for (; len < field_width; --field_width)
|
||||
ADDCH(buf, ' ');
|
||||
for (i = 0; i < utf8_len; ++i)
|
||||
ADDCH(buf, utf8[i]);
|
||||
while (utf8_len < field_width--)
|
||||
utf16_utf8_strncpy(&buf, str, len);
|
||||
for (; len < field_width; --field_width)
|
||||
ADDCH(buf, ' ');
|
||||
return buf;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_EFI_LOADER) && \
|
||||
!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
|
||||
static char *device_path_string(char *buf, char *end, void *dp, int field_width,
|
||||
int precision, int flags)
|
||||
{
|
||||
|
@ -450,8 +445,8 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|||
#endif
|
||||
|
||||
switch (*fmt) {
|
||||
#if defined(CONFIG_EFI_LOADER) && \
|
||||
!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
|
||||
/* Device paths only exist in the EFI context. */
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
case 'D':
|
||||
return device_path_string(buf, end, ptr, field_width,
|
||||
precision, flags);
|
||||
|
@ -612,10 +607,14 @@ repeat:
|
|||
continue;
|
||||
|
||||
case 's':
|
||||
if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) {
|
||||
/* U-Boot uses UTF-16 strings in the EFI context only. */
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
if (qualifier == 'l') {
|
||||
str = string16(str, end, va_arg(args, u16 *),
|
||||
field_width, precision, flags);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
str = string(str, end, va_arg(args, char *),
|
||||
field_width, precision, flags);
|
||||
}
|
||||
|
|
|
@ -4069,7 +4069,6 @@ CONFIG_SYS_RSTC_RMR_VAL
|
|||
CONFIG_SYS_RTC_BUS_NUM
|
||||
CONFIG_SYS_RTC_CNT
|
||||
CONFIG_SYS_RTC_OSCILLATOR
|
||||
CONFIG_SYS_RTC_PL031_BASE
|
||||
CONFIG_SYS_RTC_REG_BASE_ADDR
|
||||
CONFIG_SYS_RTC_SETUP
|
||||
CONFIG_SYS_RV3029_TCR
|
||||
|
|
|
@ -15,6 +15,14 @@ config UT_TIME
|
|||
problems. But if you are having problems with udelay() and the like,
|
||||
this is a good place to start.
|
||||
|
||||
config UT_UNICODE
|
||||
bool "Unit tests for Unicode functions"
|
||||
depends on UNIT_TEST
|
||||
default y
|
||||
help
|
||||
Enables the 'ut unicode' command which tests that the functions for
|
||||
manipulating Unicode strings work correctly.
|
||||
|
||||
source "test/dm/Kconfig"
|
||||
source "test/env/Kconfig"
|
||||
source "test/overlay/Kconfig"
|
||||
|
|
|
@ -8,4 +8,5 @@ obj-$(CONFIG_SANDBOX) += command_ut.o
|
|||
obj-$(CONFIG_SANDBOX) += compression.o
|
||||
obj-$(CONFIG_SANDBOX) += print_ut.o
|
||||
obj-$(CONFIG_UT_TIME) += time_ut.o
|
||||
obj-$(CONFIG_UT_UNICODE) += unicode_ut.o
|
||||
obj-$(CONFIG_$(SPL_)LOG) += log/
|
||||
|
|
|
@ -49,6 +49,9 @@ static cmd_tbl_t cmd_ut_sub[] = {
|
|||
#ifdef CONFIG_UT_TIME
|
||||
U_BOOT_CMD_MKENT(time, CONFIG_SYS_MAXARGS, 1, do_ut_time, "", ""),
|
||||
#endif
|
||||
#if CONFIG_IS_ENABLED(UT_UNICODE) && !defined(API_BUILD)
|
||||
U_BOOT_CMD_MKENT(unicode, CONFIG_SYS_MAXARGS, 1, do_ut_unicode, "", ""),
|
||||
#endif
|
||||
#ifdef CONFIG_SANDBOX
|
||||
U_BOOT_CMD_MKENT(compression, CONFIG_SYS_MAXARGS, 1, do_ut_compression,
|
||||
"", ""),
|
||||
|
@ -93,6 +96,9 @@ static int do_ut(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
|||
#ifdef CONFIG_SYS_LONGHELP
|
||||
static char ut_help_text[] =
|
||||
"all - execute all enabled tests\n"
|
||||
#ifdef CONFIG_SANDBOX
|
||||
"ut compression - Test compressors and bootm decompression\n"
|
||||
#endif
|
||||
#ifdef CONFIG_UT_DM
|
||||
"ut dm [test-name]\n"
|
||||
#endif
|
||||
|
@ -105,11 +111,12 @@ static char ut_help_text[] =
|
|||
#ifdef CONFIG_UT_TIME
|
||||
"ut time - Very basic test of time functions\n"
|
||||
#endif
|
||||
#ifdef CONFIG_SANDBOX
|
||||
"ut compression - Test compressors and bootm decompression\n"
|
||||
#if defined(CONFIG_UT_UNICODE) && \
|
||||
!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
|
||||
"ut unicode [test-name] - test Unicode functions\n"
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
#endif /* CONFIG_SYS_LONGHELP */
|
||||
|
||||
U_BOOT_CMD(
|
||||
ut, CONFIG_SYS_MAXARGS, 1, do_ut,
|
||||
|
|
|
@ -7,18 +7,20 @@
|
|||
# It currently tests the fs/sb and native commands for ext4 and fat partitions
|
||||
# Expected results are as follows:
|
||||
# EXT4 tests:
|
||||
# fs-test.sb.ext4.out: Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.ext4.out: Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.fs.ext4.out: Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.sb.ext4 Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.nonfs.ext4 Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.fs.ext4 Summary: PASS: 24 FAIL: 0
|
||||
# FAT16 tests:
|
||||
# fs-test.sb.fat16.out: Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.fat16.out: Summary: PASS: 20 FAIL: 4
|
||||
# fs-test.fs.fat16.out: Summary: PASS: 20 FAIL: 4
|
||||
# fs-test.sb.fat16 Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.nonfs.fat16 Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.fs.fat16 Summary: PASS: 24 FAIL: 0
|
||||
# FAT32 tests:
|
||||
# fs-test.sb.fat32.out: Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.fat32.out: Summary: PASS: 20 FAIL: 4
|
||||
# fs-test.fs.fat32.out: Summary: PASS: 20 FAIL: 4
|
||||
# Total Summary: TOTAL PASS: 200 TOTAL FAIL: 16
|
||||
# fs-test.sb.fat32 Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.nonfs.fat32 Summary: PASS: 24 FAIL: 0
|
||||
# fs-test.fs.fat32 Summary: PASS: 24 FAIL: 0
|
||||
# --------------------------------------------
|
||||
# Total Summary: TOTAL PASS: 216 TOTAL FAIL: 0
|
||||
# --------------------------------------------
|
||||
|
||||
# pre-requisite binaries list.
|
||||
PREREQ_BINS="md5sum mkfs mount umount dd fallocate mkdir"
|
||||
|
@ -522,7 +524,7 @@ function check_results() {
|
|||
"TC11: 1MB write to $3.w - content verified"
|
||||
|
||||
# Check lookup of 'dot' directory
|
||||
grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file'
|
||||
grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write'
|
||||
pass_fail "TC12: 1MB write to . - write denied"
|
||||
|
||||
# Check directory traversal
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
#define DEBUG
|
||||
|
||||
#include <common.h>
|
||||
#if defined(CONFIG_EFI_LOADER) && \
|
||||
!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
#include <efi_api.h>
|
||||
#endif
|
||||
#include <display_options.h>
|
||||
|
@ -19,8 +18,7 @@
|
|||
/* Test efi_loader specific printing */
|
||||
static void efi_ut_print(void)
|
||||
{
|
||||
#if defined(CONFIG_EFI_LOADER) && \
|
||||
!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
char str[10];
|
||||
u8 buf[sizeof(struct efi_device_path_sd_mmc_path) +
|
||||
sizeof(struct efi_device_path)];
|
||||
|
|
|
@ -16,7 +16,7 @@ def test_efi_selftest(u_boot_console):
|
|||
u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
|
||||
if m != 0:
|
||||
raise Exception('Failures occured during the EFI selftest')
|
||||
raise Exception('Failures occurred during the EFI selftest')
|
||||
u_boot_console.run_command(cmd='', wait_for_echo=False, wait_for_prompt=False);
|
||||
m = u_boot_console.p.expect(['resetting', 'U-Boot'])
|
||||
if m != 0:
|
||||
|
@ -48,3 +48,152 @@ def test_efi_selftest_watchdog_reboot(u_boot_console):
|
|||
if m != 0:
|
||||
raise Exception('Reset failed in \'watchdog reboot\' test')
|
||||
u_boot_console.restart_uboot();
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
|
||||
def test_efi_selftest_text_input(u_boot_console):
|
||||
"""Test the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
|
||||
|
||||
:param u_boot_console: U-Boot console
|
||||
|
||||
This function calls the text input EFI selftest.
|
||||
"""
|
||||
u_boot_console.run_command(cmd='setenv efi_selftest text input')
|
||||
output = u_boot_console.run_command(cmd='bootefi selftest',
|
||||
wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['To terminate type \'x\''])
|
||||
if m != 0:
|
||||
raise Exception('No prompt for \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
u_boot_console.p.timeout = 500
|
||||
# EOT
|
||||
u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 4 \(unknown\), scan code 0 \(Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('EOT failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# BS
|
||||
u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 8 \(BS\), scan code 0 \(Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('BS failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# TAB
|
||||
u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 9 \(TAB\), scan code 0 \(Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('BS failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# a
|
||||
u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
|
||||
wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('\'a\' failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# UP escape sequence
|
||||
u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 0 \(Null\), scan code 1 \(Up\)'])
|
||||
if m != 0:
|
||||
raise Exception('UP failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# Euro sign
|
||||
u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['Unicode char 8364 \(\''])
|
||||
if m != 0:
|
||||
raise Exception('Euro sign failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
u_boot_console.run_command(cmd='x', wait_for_echo=False, send_nl=False,
|
||||
wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
|
||||
if m != 0:
|
||||
raise Exception('Failures occurred during the EFI selftest')
|
||||
u_boot_console.restart_uboot();
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
|
||||
def test_efi_selftest_text_input_ex(u_boot_console):
|
||||
"""Test the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
|
||||
|
||||
:param u_boot_console: U-Boot console
|
||||
|
||||
This function calls the extended text input EFI selftest.
|
||||
"""
|
||||
u_boot_console.run_command(cmd='setenv efi_selftest extended text input')
|
||||
output = u_boot_console.run_command(cmd='bootefi selftest',
|
||||
wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['To terminate type \'CTRL\+x\''])
|
||||
if m != 0:
|
||||
raise Exception('No prompt for \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
u_boot_console.p.timeout = 500
|
||||
# EOT
|
||||
u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 4 \(unknown\), scan code 0 \(CTRL\+Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('EOT failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# BS
|
||||
u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 8 \(BS\), scan code 0 \(\+Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('BS failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# TAB
|
||||
u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 9 \(TAB\), scan code 0 \(\+Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('TAB failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# a
|
||||
u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
|
||||
wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
|
||||
if m != 0:
|
||||
raise Exception('\'a\' failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# UP escape sequence
|
||||
u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 0 \(Null\), scan code 1 \(\+Up\)'])
|
||||
if m != 0:
|
||||
raise Exception('UP failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# Euro sign
|
||||
u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False,
|
||||
send_nl=False, wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['Unicode char 8364 \(\''])
|
||||
if m != 0:
|
||||
raise Exception('Euro sign failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
# SHIFT+ALT+FN 5
|
||||
u_boot_console.run_command(cmd='\x1b\x5b\x31\x35\x3b\x34\x7e',
|
||||
wait_for_echo=False, send_nl=False,
|
||||
wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(
|
||||
['Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)'])
|
||||
if m != 0:
|
||||
raise Exception('SHIFT+ALT+FN 5 failed in \'text input\' test')
|
||||
u_boot_console.drain_console()
|
||||
u_boot_console.run_command(cmd=chr(24), wait_for_echo=False, send_nl=False,
|
||||
wait_for_prompt=False)
|
||||
m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
|
||||
if m != 0:
|
||||
raise Exception('Failures occurred during the EFI selftest')
|
||||
u_boot_console.restart_uboot();
|
||||
|
|
392
test/py/tests/test_fs/conftest.py
Normal file
392
test/py/tests/test_fs/conftest.py
Normal file
|
@ -0,0 +1,392 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018, Linaro Limited
|
||||
# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import pytest
|
||||
import re
|
||||
from subprocess import call, check_call, check_output, CalledProcessError
|
||||
from fstest_defs import *
|
||||
|
||||
supported_fs_basic = ['fat16', 'fat32', 'ext4']
|
||||
supported_fs_ext = ['fat16', 'fat32']
|
||||
supported_fs_mkdir = ['fat16', 'fat32']
|
||||
supported_fs_unlink = ['fat16', 'fat32']
|
||||
|
||||
#
|
||||
# Filesystem test specific setup
|
||||
#
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption('--fs-type', action='append', default=None,
|
||||
help='Targeting Filesystem Types')
|
||||
|
||||
def pytest_configure(config):
|
||||
global supported_fs_basic
|
||||
global supported_fs_ext
|
||||
global supported_fs_mkdir
|
||||
global supported_fs_unlink
|
||||
|
||||
def intersect(listA, listB):
|
||||
return [x for x in listA if x in listB]
|
||||
|
||||
supported_fs = config.getoption('fs_type')
|
||||
if supported_fs:
|
||||
print("*** FS TYPE modified: %s" % supported_fs)
|
||||
supported_fs_basic = intersect(supported_fs, supported_fs_basic)
|
||||
supported_fs_ext = intersect(supported_fs, supported_fs_ext)
|
||||
supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir)
|
||||
supported_fs_unlink = intersect(supported_fs, supported_fs_unlink)
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if 'fs_obj_basic' in metafunc.fixturenames:
|
||||
metafunc.parametrize('fs_obj_basic', supported_fs_basic,
|
||||
indirect=True, scope='module')
|
||||
if 'fs_obj_ext' in metafunc.fixturenames:
|
||||
metafunc.parametrize('fs_obj_ext', supported_fs_ext,
|
||||
indirect=True, scope='module')
|
||||
if 'fs_obj_mkdir' in metafunc.fixturenames:
|
||||
metafunc.parametrize('fs_obj_mkdir', supported_fs_mkdir,
|
||||
indirect=True, scope='module')
|
||||
if 'fs_obj_unlink' in metafunc.fixturenames:
|
||||
metafunc.parametrize('fs_obj_unlink', supported_fs_unlink,
|
||||
indirect=True, scope='module')
|
||||
|
||||
#
|
||||
# Helper functions
|
||||
#
|
||||
def fstype_to_ubname(fs_type):
|
||||
if re.match('fat', fs_type):
|
||||
return 'fat'
|
||||
else:
|
||||
return fs_type
|
||||
|
||||
def check_ubconfig(config, fs_type):
|
||||
if not config.buildconfig.get('config_cmd_%s' % fs_type, None):
|
||||
pytest.skip('.config feature "CMD_%s" not enabled' % fs_type.upper())
|
||||
if not config.buildconfig.get('config_%s_write' % fs_type, None):
|
||||
pytest.skip('.config feature "%s_WRITE" not enabled'
|
||||
% fs_type.upper())
|
||||
|
||||
def mk_fs(config, fs_type, size, id):
|
||||
fs_img = '%s.%s.img' % (id, fs_type)
|
||||
fs_img = config.persistent_data_dir + '/' + fs_img
|
||||
|
||||
if fs_type == 'fat16':
|
||||
mkfs_opt = '-F 16'
|
||||
elif fs_type == 'fat32':
|
||||
mkfs_opt = '-F 32'
|
||||
else:
|
||||
mkfs_opt = ''
|
||||
|
||||
if re.match('fat', fs_type):
|
||||
fs_lnxtype = 'vfat'
|
||||
else:
|
||||
fs_lnxtype = fs_type
|
||||
|
||||
count = (size + 1048576 - 1) / 1048576
|
||||
|
||||
try:
|
||||
check_call('rm -f %s' % fs_img, shell=True)
|
||||
check_call('dd if=/dev/zero of=%s bs=1M count=%d'
|
||||
% (fs_img, count), shell=True)
|
||||
check_call('mkfs.%s %s %s'
|
||||
% (fs_lnxtype, mkfs_opt, fs_img), shell=True)
|
||||
return fs_img
|
||||
except CalledProcessError:
|
||||
call('rm -f %s' % fs_img, shell=True)
|
||||
raise
|
||||
|
||||
# from test/py/conftest.py
|
||||
def tool_is_in_path(tool):
|
||||
for path in os.environ["PATH"].split(os.pathsep):
|
||||
fn = os.path.join(path, tool)
|
||||
if os.path.isfile(fn) and os.access(fn, os.X_OK):
|
||||
return True
|
||||
return False
|
||||
|
||||
fuse_mounted = False
|
||||
|
||||
def mount_fs(fs_type, device, mount_point):
|
||||
global fuse_mounted
|
||||
|
||||
fuse_mounted = False
|
||||
try:
|
||||
if tool_is_in_path('guestmount'):
|
||||
fuse_mounted = True
|
||||
check_call('guestmount -a %s -m /dev/sda %s'
|
||||
% (device, mount_point), shell=True)
|
||||
else:
|
||||
mount_opt = "loop,rw"
|
||||
if re.match('fat', fs_type):
|
||||
mount_opt += ",umask=0000"
|
||||
|
||||
check_call('sudo mount -o %s %s %s'
|
||||
% (mount_opt, device, mount_point), shell=True)
|
||||
|
||||
# may not be effective for some file systems
|
||||
check_call('sudo chmod a+rw %s' % mount_point, shell=True)
|
||||
except CalledProcessError:
|
||||
raise
|
||||
|
||||
def umount_fs(fs_type, mount_point):
|
||||
if fuse_mounted:
|
||||
call('sync')
|
||||
call('guestunmount %s' % mount_point, shell=True)
|
||||
else:
|
||||
call('sudo umount %s' % mount_point, shell=True)
|
||||
|
||||
#
|
||||
# Fixture for basic fs test
|
||||
# derived from test/fs/fs-test.sh
|
||||
#
|
||||
# NOTE: yield_fixture was deprecated since pytest-3.0
|
||||
@pytest.yield_fixture()
|
||||
def fs_obj_basic(request, u_boot_config):
|
||||
fs_type = request.param
|
||||
fs_img = ''
|
||||
|
||||
fs_ubtype = fstype_to_ubname(fs_type)
|
||||
check_ubconfig(u_boot_config, fs_ubtype)
|
||||
|
||||
mount_dir = u_boot_config.persistent_data_dir + '/mnt'
|
||||
|
||||
small_file = mount_dir + '/' + SMALL_FILE
|
||||
big_file = mount_dir + '/' + BIG_FILE
|
||||
|
||||
try:
|
||||
|
||||
# 3GiB volume
|
||||
fs_img = mk_fs(u_boot_config, fs_type, 0xc0000000, '3GB')
|
||||
|
||||
# Mount the image so we can populate it.
|
||||
check_call('mkdir -p %s' % mount_dir, shell=True)
|
||||
mount_fs(fs_type, fs_img, mount_dir)
|
||||
|
||||
# Create a subdirectory.
|
||||
check_call('mkdir %s/SUBDIR' % mount_dir, shell=True)
|
||||
|
||||
# Create big file in this image.
|
||||
# Note that we work only on the start 1MB, couple MBs in the 2GB range
|
||||
# and the last 1 MB of the huge 2.5GB file.
|
||||
# So, just put random values only in those areas.
|
||||
check_call('dd if=/dev/urandom of=%s bs=1M count=1'
|
||||
% big_file, shell=True)
|
||||
check_call('dd if=/dev/urandom of=%s bs=1M count=2 seek=2047'
|
||||
% big_file, shell=True)
|
||||
check_call('dd if=/dev/urandom of=%s bs=1M count=1 seek=2499'
|
||||
% big_file, shell=True)
|
||||
|
||||
# Create a small file in this image.
|
||||
check_call('dd if=/dev/urandom of=%s bs=1M count=1'
|
||||
% small_file, shell=True)
|
||||
|
||||
# Delete the small file copies which possibly are written as part of a
|
||||
# previous test.
|
||||
# check_call('rm -f "%s.w"' % MB1, shell=True)
|
||||
# check_call('rm -f "%s.w2"' % MB1, shell=True)
|
||||
|
||||
# Generate the md5sums of reads that we will test against small file
|
||||
out = check_output(
|
||||
'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
|
||||
% small_file, shell=True)
|
||||
md5val = [ out.split()[0] ]
|
||||
|
||||
# Generate the md5sums of reads that we will test against big file
|
||||
# One from beginning of file.
|
||||
out = check_output(
|
||||
'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
|
||||
% big_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
# One from end of file.
|
||||
out = check_output(
|
||||
'dd if=%s bs=1M skip=2499 count=1 2> /dev/null | md5sum'
|
||||
% big_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
# One from the last 1MB chunk of 2GB
|
||||
out = check_output(
|
||||
'dd if=%s bs=1M skip=2047 count=1 2> /dev/null | md5sum'
|
||||
% big_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
# One from the start 1MB chunk from 2GB
|
||||
out = check_output(
|
||||
'dd if=%s bs=1M skip=2048 count=1 2> /dev/null | md5sum'
|
||||
% big_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
# One 1MB chunk crossing the 2GB boundary
|
||||
out = check_output(
|
||||
'dd if=%s bs=512K skip=4095 count=2 2> /dev/null | md5sum'
|
||||
% big_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
umount_fs(fs_type, mount_dir)
|
||||
except CalledProcessError:
|
||||
pytest.skip('Setup failed for filesystem: ' + fs_type)
|
||||
return
|
||||
else:
|
||||
yield [fs_ubtype, fs_img, md5val]
|
||||
finally:
|
||||
umount_fs(fs_type, mount_dir)
|
||||
call('rmdir %s' % mount_dir, shell=True)
|
||||
if fs_img:
|
||||
call('rm -f %s' % fs_img, shell=True)
|
||||
|
||||
#
|
||||
# Fixture for extended fs test
|
||||
#
|
||||
# NOTE: yield_fixture was deprecated since pytest-3.0
|
||||
@pytest.yield_fixture()
|
||||
def fs_obj_ext(request, u_boot_config):
|
||||
fs_type = request.param
|
||||
fs_img = ''
|
||||
|
||||
fs_ubtype = fstype_to_ubname(fs_type)
|
||||
check_ubconfig(u_boot_config, fs_ubtype)
|
||||
|
||||
mount_dir = u_boot_config.persistent_data_dir + '/mnt'
|
||||
|
||||
min_file = mount_dir + '/' + MIN_FILE
|
||||
tmp_file = mount_dir + '/tmpfile'
|
||||
|
||||
try:
|
||||
|
||||
# 128MiB volume
|
||||
fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
|
||||
|
||||
# Mount the image so we can populate it.
|
||||
check_call('mkdir -p %s' % mount_dir, shell=True)
|
||||
mount_fs(fs_type, fs_img, mount_dir)
|
||||
|
||||
# Create a test directory
|
||||
check_call('mkdir %s/dir1' % mount_dir, shell=True)
|
||||
|
||||
# Create a small file and calculate md5
|
||||
check_call('dd if=/dev/urandom of=%s bs=1K count=20'
|
||||
% min_file, shell=True)
|
||||
out = check_output(
|
||||
'dd if=%s bs=1K 2> /dev/null | md5sum'
|
||||
% min_file, shell=True)
|
||||
md5val = [ out.split()[0] ]
|
||||
|
||||
# Calculate md5sum of Test Case 4
|
||||
check_call('dd if=%s of=%s bs=1K count=20'
|
||||
% (min_file, tmp_file), shell=True)
|
||||
check_call('dd if=%s of=%s bs=1K seek=5 count=20'
|
||||
% (min_file, tmp_file), shell=True)
|
||||
out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
|
||||
% tmp_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
# Calculate md5sum of Test Case 5
|
||||
check_call('dd if=%s of=%s bs=1K count=20'
|
||||
% (min_file, tmp_file), shell=True)
|
||||
check_call('dd if=%s of=%s bs=1K seek=5 count=5'
|
||||
% (min_file, tmp_file), shell=True)
|
||||
out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
|
||||
% tmp_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
# Calculate md5sum of Test Case 7
|
||||
check_call('dd if=%s of=%s bs=1K count=20'
|
||||
% (min_file, tmp_file), shell=True)
|
||||
check_call('dd if=%s of=%s bs=1K seek=20 count=20'
|
||||
% (min_file, tmp_file), shell=True)
|
||||
out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
|
||||
% tmp_file, shell=True)
|
||||
md5val.append(out.split()[0])
|
||||
|
||||
check_call('rm %s' % tmp_file, shell=True)
|
||||
umount_fs(fs_type, mount_dir)
|
||||
except CalledProcessError:
|
||||
pytest.skip('Setup failed for filesystem: ' + fs_type)
|
||||
return
|
||||
else:
|
||||
yield [fs_ubtype, fs_img, md5val]
|
||||
finally:
|
||||
umount_fs(fs_type, mount_dir)
|
||||
call('rmdir %s' % mount_dir, shell=True)
|
||||
if fs_img:
|
||||
call('rm -f %s' % fs_img, shell=True)
|
||||
|
||||
#
|
||||
# Fixture for mkdir test
|
||||
#
|
||||
# NOTE: yield_fixture was deprecated since pytest-3.0
|
||||
@pytest.yield_fixture()
|
||||
def fs_obj_mkdir(request, u_boot_config):
|
||||
fs_type = request.param
|
||||
fs_img = ''
|
||||
|
||||
fs_ubtype = fstype_to_ubname(fs_type)
|
||||
check_ubconfig(u_boot_config, fs_ubtype)
|
||||
|
||||
try:
|
||||
# 128MiB volume
|
||||
fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
|
||||
except:
|
||||
pytest.skip('Setup failed for filesystem: ' + fs_type)
|
||||
else:
|
||||
yield [fs_ubtype, fs_img]
|
||||
finally:
|
||||
if fs_img:
|
||||
call('rm -f %s' % fs_img, shell=True)
|
||||
|
||||
#
|
||||
# Fixture for unlink test
|
||||
#
|
||||
# NOTE: yield_fixture was deprecated since pytest-3.0
|
||||
@pytest.yield_fixture()
|
||||
def fs_obj_unlink(request, u_boot_config):
|
||||
fs_type = request.param
|
||||
fs_img = ''
|
||||
|
||||
fs_ubtype = fstype_to_ubname(fs_type)
|
||||
check_ubconfig(u_boot_config, fs_ubtype)
|
||||
|
||||
mount_dir = u_boot_config.persistent_data_dir + '/mnt'
|
||||
|
||||
try:
|
||||
|
||||
# 128MiB volume
|
||||
fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
|
||||
|
||||
# Mount the image so we can populate it.
|
||||
check_call('mkdir -p %s' % mount_dir, shell=True)
|
||||
mount_fs(fs_type, fs_img, mount_dir)
|
||||
|
||||
# Test Case 1 & 3
|
||||
check_call('mkdir %s/dir1' % mount_dir, shell=True)
|
||||
check_call('dd if=/dev/urandom of=%s/dir1/file1 bs=1K count=1'
|
||||
% mount_dir, shell=True)
|
||||
check_call('dd if=/dev/urandom of=%s/dir1/file2 bs=1K count=1'
|
||||
% mount_dir, shell=True)
|
||||
|
||||
# Test Case 2
|
||||
check_call('mkdir %s/dir2' % mount_dir, shell=True)
|
||||
for i in range(0, 20):
|
||||
check_call('mkdir %s/dir2/0123456789abcdef%02x'
|
||||
% (mount_dir, i), shell=True)
|
||||
|
||||
# Test Case 4
|
||||
check_call('mkdir %s/dir4' % mount_dir, shell=True)
|
||||
|
||||
# Test Case 5, 6 & 7
|
||||
check_call('mkdir %s/dir5' % mount_dir, shell=True)
|
||||
check_call('dd if=/dev/urandom of=%s/dir5/file1 bs=1K count=1'
|
||||
% mount_dir, shell=True)
|
||||
|
||||
umount_fs(fs_type, mount_dir)
|
||||
except CalledProcessError:
|
||||
pytest.skip('Setup failed for filesystem: ' + fs_type)
|
||||
return
|
||||
else:
|
||||
yield [fs_ubtype, fs_img]
|
||||
finally:
|
||||
umount_fs(fs_type, mount_dir)
|
||||
call('rmdir %s' % mount_dir, shell=True)
|
||||
if fs_img:
|
||||
call('rm -f %s' % fs_img, shell=True)
|
13
test/py/tests/test_fs/fstest_defs.py
Normal file
13
test/py/tests/test_fs/fstest_defs.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
# $MIN_FILE is the name of the 20KB file in the file system image
|
||||
MIN_FILE='testfile'
|
||||
|
||||
# $SMALL_FILE is the name of the 1MB file in the file system image
|
||||
SMALL_FILE='1MB.file'
|
||||
|
||||
# $BIG_FILE is the name of the 2.5GB file in the file system image
|
||||
BIG_FILE='2.5GB.file'
|
||||
|
||||
ADDR=0x01000008
|
||||
LENGTH=0x00100000
|
287
test/py/tests/test_fs/test_basic.py
Normal file
287
test/py/tests/test_fs/test_basic.py
Normal file
|
@ -0,0 +1,287 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018, Linaro Limited
|
||||
# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
|
||||
#
|
||||
# U-Boot File System:Basic Test
|
||||
|
||||
"""
|
||||
This test verifies basic read/write operation on file system.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import re
|
||||
from fstest_defs import *
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
class TestFsBasic(object):
|
||||
def test_fs1(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 1 - ls command, listing a root directory and invalid directory
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 1a - ls'):
|
||||
# Test Case 1 - ls
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sls host 0:0' % fs_type])
|
||||
assert(re.search('2621440000 *%s' % BIG_FILE, ''.join(output)))
|
||||
assert(re.search('1048576 *%s' % SMALL_FILE, ''.join(output)))
|
||||
|
||||
with u_boot_console.log.section('Test Case 1b - ls (invalid dir)'):
|
||||
# In addition, test with a nonexistent directory to see if we crash.
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 invalid_d' % fs_type)
|
||||
if fs_type == 'ext4':
|
||||
assert('Can not find directory' in output)
|
||||
else:
|
||||
assert('' == output)
|
||||
|
||||
def test_fs2(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 2 - size command for a small file
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 2a - size (small)'):
|
||||
# 1MB is 0x0010 0000
|
||||
# Test Case 2a - size of small file
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%ssize host 0:0 /%s' % (fs_type, SMALL_FILE),
|
||||
'printenv filesize',
|
||||
'setenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
with u_boot_console.log.section('Test Case 2b - size (/../<file>)'):
|
||||
# Test Case 2b - size of small file via a path using '..'
|
||||
output = u_boot_console.run_command_list([
|
||||
'%ssize host 0:0 /SUBDIR/../%s' % (fs_type, SMALL_FILE),
|
||||
'printenv filesize',
|
||||
'setenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
def test_fs3(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 3 - size command for a large file
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 3 - size (large)'):
|
||||
# 2.5GB (1024*1024*2500) is 0x9C40 0000
|
||||
# Test Case 3 - size of big file
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%ssize host 0:0 /%s' % (fs_type, BIG_FILE),
|
||||
'printenv filesize',
|
||||
'setenv filesize'])
|
||||
assert('filesize=9c400000' in ''.join(output))
|
||||
|
||||
def test_fs4(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 4 - load a small file, 1MB
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 4 - load (small)'):
|
||||
# Test Case 4a - Read full 1MB of small file
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
|
||||
'printenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
# Test Case 4b - Read full 1MB of small file
|
||||
output = u_boot_console.run_command_list([
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[0] in ''.join(output))
|
||||
|
||||
def test_fs5(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 5 - load, reading first 1MB of 3GB file
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 5 - load (first 1MB)'):
|
||||
# Test Case 5a - First 1MB of big file
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s %x 0x0' % (fs_type, ADDR, BIG_FILE, LENGTH),
|
||||
'printenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
# Test Case 5b - First 1MB of big file
|
||||
output = u_boot_console.run_command_list([
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[1] in ''.join(output))
|
||||
|
||||
def test_fs6(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 6 - load, reading last 1MB of 3GB file
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 6 - load (last 1MB)'):
|
||||
# fails for ext as no offset support
|
||||
# Test Case 6a - Last 1MB of big file
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s %x 0x9c300000'
|
||||
% (fs_type, ADDR, BIG_FILE, LENGTH),
|
||||
'printenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
# Test Case 6b - Last 1MB of big file
|
||||
output = u_boot_console.run_command_list([
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[2] in ''.join(output))
|
||||
|
||||
def test_fs7(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 7 - load, 1MB from the last 1MB in 2GB
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 7 - load (last 1MB in 2GB)'):
|
||||
# fails for ext as no offset support
|
||||
# Test Case 7a - One from the last 1MB chunk of 2GB
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s %x 0x7ff00000'
|
||||
% (fs_type, ADDR, BIG_FILE, LENGTH),
|
||||
'printenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
# Test Case 7b - One from the last 1MB chunk of 2GB
|
||||
output = u_boot_console.run_command_list([
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[3] in ''.join(output))
|
||||
|
||||
def test_fs8(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 8 - load, reading first 1MB in 2GB
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 8 - load (first 1MB in 2GB)'):
|
||||
# fails for ext as no offset support
|
||||
# Test Case 8a - One from the start 1MB chunk from 2GB
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s %x 0x80000000'
|
||||
% (fs_type, ADDR, BIG_FILE, LENGTH),
|
||||
'printenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
# Test Case 8b - One from the start 1MB chunk from 2GB
|
||||
output = u_boot_console.run_command_list([
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[4] in ''.join(output))
|
||||
|
||||
def test_fs9(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 9 - load, 1MB crossing 2GB boundary
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 9 - load (crossing 2GB boundary)'):
|
||||
# fails for ext as no offset support
|
||||
# Test Case 9a - One 1MB chunk crossing the 2GB boundary
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s %x 0x7ff80000'
|
||||
% (fs_type, ADDR, BIG_FILE, LENGTH),
|
||||
'printenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
# Test Case 9b - One 1MB chunk crossing the 2GB boundary
|
||||
output = u_boot_console.run_command_list([
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[5] in ''.join(output))
|
||||
|
||||
def test_fs10(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 10 - load, reading beyond file end'):
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 10 - load (beyond file end)'):
|
||||
# Generic failure case
|
||||
# Test Case 10 - 2MB chunk from the last 1MB of big file
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s 0x00200000 0x9c300000'
|
||||
% (fs_type, ADDR, BIG_FILE),
|
||||
'printenv filesize',
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert('filesize=100000' in ''.join(output))
|
||||
|
||||
def test_fs11(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 11 - write'
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 11 - write'):
|
||||
# Read 1MB from small file
|
||||
# Write it back to test the writes
|
||||
# Test Case 11a - Check that the write succeeded
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
|
||||
'%swrite host 0:0 %x /%s.w $filesize'
|
||||
% (fs_type, ADDR, SMALL_FILE)])
|
||||
assert('1048576 bytes written' in ''.join(output))
|
||||
|
||||
# Test Case 11b - Check md5 of written to is same
|
||||
# as the one read from
|
||||
output = u_boot_console.run_command_list([
|
||||
'%sload host 0:0 %x /%s.w' % (fs_type, ADDR, SMALL_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[0] in ''.join(output))
|
||||
|
||||
def test_fs12(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 12 - write to "." directory
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 12 - write (".")'):
|
||||
# Next test case checks writing a file whose dirent
|
||||
# is the first in the block, which is always true for "."
|
||||
# The write should fail, but the lookup should work
|
||||
# Test Case 12 - Check directory traversal
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%swrite host 0:0 %x /. 0x10' % (fs_type, ADDR)])
|
||||
assert('Unable to write' in ''.join(output))
|
||||
|
||||
def test_fs13(self, u_boot_console, fs_obj_basic):
|
||||
"""
|
||||
Test Case 13 - write to a file with "/./<filename>"
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_basic
|
||||
with u_boot_console.log.section('Test Case 13 - write ("./<file>")'):
|
||||
# Read 1MB from small file
|
||||
# Write it via "same directory", i.e. "." dirent
|
||||
# Test Case 13a - Check directory traversal
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
|
||||
'%swrite host 0:0 %x /./%s2 $filesize'
|
||||
% (fs_type, ADDR, SMALL_FILE)])
|
||||
assert('1048576 bytes written' in ''.join(output))
|
||||
|
||||
# Test Case 13b - Check md5 of written to is same
|
||||
# as the one read from
|
||||
output = u_boot_console.run_command_list([
|
||||
'mw.b %x 00 100' % ADDR,
|
||||
'%sload host 0:0 %x /./%s2' % (fs_type, ADDR, SMALL_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[0] in ''.join(output))
|
||||
|
||||
# Test Case 13c - Check md5 of written to is same
|
||||
# as the one read from
|
||||
output = u_boot_console.run_command_list([
|
||||
'mw.b %x 00 100' % ADDR,
|
||||
'%sload host 0:0 %x /%s2' % (fs_type, ADDR, SMALL_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[0] in ''.join(output))
|
224
test/py/tests/test_fs/test_ext.py
Normal file
224
test/py/tests/test_fs/test_ext.py
Normal file
|
@ -0,0 +1,224 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018, Linaro Limited
|
||||
# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
|
||||
#
|
||||
# U-Boot File System:Exntented Test
|
||||
|
||||
"""
|
||||
This test verifies extended write operation on file system.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import re
|
||||
from fstest_defs import *
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
class TestFsExt(object):
|
||||
def test_fs_ext1(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 1 - write a file with absolute path
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 1 - write with abs path'):
|
||||
# Test Case 1a - Check if command successfully returned
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/%s.w1 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
assert('20480 bytes written' in ''.join(output))
|
||||
|
||||
# Test Case 1b - Check md5 of file content
|
||||
output = u_boot_console.run_command_list([
|
||||
'mw.b %x 00 100' % ADDR,
|
||||
'%sload host 0:0 %x /dir1/%s.w1' % (fs_type, ADDR, MIN_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[0] in ''.join(output))
|
||||
|
||||
def test_fs_ext2(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 2 - write to a file with relative path
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 2 - write with rel path'):
|
||||
# Test Case 2a - Check if command successfully returned
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x dir1/%s.w2 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
assert('20480 bytes written' in ''.join(output))
|
||||
|
||||
# Test Case 2b - Check md5 of file content
|
||||
output = u_boot_console.run_command_list([
|
||||
'mw.b %x 00 100' % ADDR,
|
||||
'%sload host 0:0 %x dir1/%s.w2' % (fs_type, ADDR, MIN_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[0] in ''.join(output))
|
||||
|
||||
def test_fs_ext3(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 3 - write to a file with invalid path
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 3 - write with invalid path'):
|
||||
# Test Case 3 - Check if command expectedly failed
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/none/%s.w3 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
assert('Unable to write "/dir1/none/' in ''.join(output))
|
||||
|
||||
def test_fs_ext4(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 4 - write at non-zero offset, enlarging file size
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 4 - write at non-zero offset, enlarging file size'):
|
||||
# Test Case 4a - Check if command successfully returned
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/%s.w4 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
output = u_boot_console.run_command(
|
||||
'%swrite host 0:0 %x /dir1/%s.w4 $filesize 0x1400'
|
||||
% (fs_type, ADDR, MIN_FILE))
|
||||
assert('20480 bytes written' in output)
|
||||
|
||||
# Test Case 4b - Check size of written file
|
||||
output = u_boot_console.run_command_list([
|
||||
'%ssize host 0:0 /dir1/%s.w4' % (fs_type, MIN_FILE),
|
||||
'printenv filesize',
|
||||
'setenv filesize'])
|
||||
assert('filesize=6400' in ''.join(output))
|
||||
|
||||
# Test Case 4c - Check md5 of file content
|
||||
output = u_boot_console.run_command_list([
|
||||
'mw.b %x 00 100' % ADDR,
|
||||
'%sload host 0:0 %x /dir1/%s.w4' % (fs_type, ADDR, MIN_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[1] in ''.join(output))
|
||||
|
||||
def test_fs_ext5(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 5 - write at non-zero offset, shrinking file size
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 5 - write at non-zero offset, shrinking file size'):
|
||||
# Test Case 5a - Check if command successfully returned
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/%s.w5 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
output = u_boot_console.run_command(
|
||||
'%swrite host 0:0 %x /dir1/%s.w5 0x1400 0x1400'
|
||||
% (fs_type, ADDR, MIN_FILE))
|
||||
assert('5120 bytes written' in output)
|
||||
|
||||
# Test Case 5b - Check size of written file
|
||||
output = u_boot_console.run_command_list([
|
||||
'%ssize host 0:0 /dir1/%s.w5' % (fs_type, MIN_FILE),
|
||||
'printenv filesize',
|
||||
'setenv filesize'])
|
||||
assert('filesize=2800' in ''.join(output))
|
||||
|
||||
# Test Case 5c - Check md5 of file content
|
||||
output = u_boot_console.run_command_list([
|
||||
'mw.b %x 00 100' % ADDR,
|
||||
'%sload host 0:0 %x /dir1/%s.w5' % (fs_type, ADDR, MIN_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[2] in ''.join(output))
|
||||
|
||||
def test_fs_ext6(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 6 - write nothing at the start, truncating to zero
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 6 - write nothing at the start, truncating to zero'):
|
||||
# Test Case 6a - Check if command successfully returned
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/%s.w6 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
output = u_boot_console.run_command(
|
||||
'%swrite host 0:0 %x /dir1/%s.w6 0 0'
|
||||
% (fs_type, ADDR, MIN_FILE))
|
||||
assert('0 bytes written' in output)
|
||||
|
||||
# Test Case 6b - Check size of written file
|
||||
output = u_boot_console.run_command_list([
|
||||
'%ssize host 0:0 /dir1/%s.w6' % (fs_type, MIN_FILE),
|
||||
'printenv filesize',
|
||||
'setenv filesize'])
|
||||
assert('filesize=0' in ''.join(output))
|
||||
|
||||
def test_fs_ext7(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 7 - write at the end (append)
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 7 - write at the end (append)'):
|
||||
# Test Case 7a - Check if command successfully returned
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/%s.w7 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
output = u_boot_console.run_command(
|
||||
'%swrite host 0:0 %x /dir1/%s.w7 $filesize $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE))
|
||||
assert('20480 bytes written' in output)
|
||||
|
||||
# Test Case 7b - Check size of written file
|
||||
output = u_boot_console.run_command_list([
|
||||
'%ssize host 0:0 /dir1/%s.w7' % (fs_type, MIN_FILE),
|
||||
'printenv filesize',
|
||||
'setenv filesize'])
|
||||
assert('filesize=a000' in ''.join(output))
|
||||
|
||||
# Test Case 7c - Check md5 of file content
|
||||
output = u_boot_console.run_command_list([
|
||||
'mw.b %x 00 100' % ADDR,
|
||||
'%sload host 0:0 %x /dir1/%s.w7' % (fs_type, ADDR, MIN_FILE),
|
||||
'md5sum %x $filesize' % ADDR,
|
||||
'setenv filesize'])
|
||||
assert(md5val[3] in ''.join(output))
|
||||
|
||||
def test_fs_ext8(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 8 - write at offset beyond the end of file
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 8 - write beyond the end'):
|
||||
# Test Case 8a - Check if command expectedly failed
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/%s.w8 $filesize'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
output = u_boot_console.run_command(
|
||||
'%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x'
|
||||
% (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400))
|
||||
assert('Unable to write "/dir1' in output)
|
||||
|
||||
def test_fs_ext9(self, u_boot_console, fs_obj_ext):
|
||||
"""
|
||||
Test Case 9 - write to a non-existing file at non-zero offset
|
||||
"""
|
||||
fs_type,fs_img,md5val = fs_obj_ext
|
||||
with u_boot_console.log.section('Test Case 9 - write to non-existing file with non-zero offset'):
|
||||
# Test Case 9a - Check if command expectedly failed
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
|
||||
'%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400'
|
||||
% (fs_type, ADDR, MIN_FILE)])
|
||||
assert('Unable to write "/dir1' in ''.join(output))
|
112
test/py/tests/test_fs/test_mkdir.py
Normal file
112
test/py/tests/test_fs/test_mkdir.py
Normal file
|
@ -0,0 +1,112 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018, Linaro Limited
|
||||
# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
|
||||
#
|
||||
# U-Boot File System:mkdir Test
|
||||
|
||||
"""
|
||||
This test verifies mkdir operation on file system.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
class TestMkdir(object):
|
||||
def test_mkdir1(self, u_boot_console, fs_obj_mkdir):
|
||||
"""
|
||||
Test Case 1 - create a directory under a root
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_mkdir
|
||||
with u_boot_console.log.section('Test Case 1 - mkdir'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%smkdir host 0:0 dir1' % fs_type,
|
||||
'%sls host 0:0 /' % fs_type])
|
||||
assert('dir1/' in ''.join(output))
|
||||
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 dir1' % fs_type)
|
||||
assert('./' in output)
|
||||
assert('../' in output)
|
||||
|
||||
def test_mkdir2(self, u_boot_console, fs_obj_mkdir):
|
||||
"""
|
||||
Test Case 2 - create a directory under a sub-directory
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_mkdir
|
||||
with u_boot_console.log.section('Test Case 2 - mkdir (sub-sub directory)'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%smkdir host 0:0 dir1/dir2' % fs_type,
|
||||
'%sls host 0:0 dir1' % fs_type])
|
||||
assert('dir2/' in ''.join(output))
|
||||
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 dir1/dir2' % fs_type)
|
||||
assert('./' in output)
|
||||
assert('../' in output)
|
||||
|
||||
def test_mkdir3(self, u_boot_console, fs_obj_mkdir):
|
||||
"""
|
||||
Test Case 3 - trying to create a directory with a non-existing
|
||||
path should fail
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_mkdir
|
||||
with u_boot_console.log.section('Test Case 3 - mkdir (non-existing path)'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%smkdir host 0:0 none/dir3' % fs_type])
|
||||
assert('Unable to create a directory' in ''.join(output))
|
||||
|
||||
def test_mkdir4(self, u_boot_console, fs_obj_mkdir):
|
||||
"""
|
||||
Test Case 4 - trying to create "." should fail
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_mkdir
|
||||
with u_boot_console.log.section('Test Case 4 - mkdir (".")'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%smkdir host 0:0 .' % fs_type])
|
||||
assert('Unable to create a directory' in ''.join(output))
|
||||
|
||||
def test_mkdir5(self, u_boot_console, fs_obj_mkdir):
|
||||
"""
|
||||
Test Case 5 - trying to create ".." should fail
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_mkdir
|
||||
with u_boot_console.log.section('Test Case 5 - mkdir ("..")'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%smkdir host 0:0 ..' % fs_type])
|
||||
assert('Unable to create a directory' in ''.join(output))
|
||||
|
||||
def test_mkdir6(self, u_boot_console, fs_obj_mkdir):
|
||||
"""
|
||||
'Test Case 6 - create as many directories as amount of directory
|
||||
entries goes beyond a cluster size)'
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_mkdir
|
||||
with u_boot_console.log.section('Test Case 6 - mkdir (create many)'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%smkdir host 0:0 dir6' % fs_type,
|
||||
'%sls host 0:0 /' % fs_type])
|
||||
assert('dir6/' in ''.join(output))
|
||||
|
||||
for i in range(0, 20):
|
||||
output = u_boot_console.run_command(
|
||||
'%smkdir host 0:0 dir6/0123456789abcdef%02x'
|
||||
% (fs_type, i))
|
||||
output = u_boot_console.run_command('%sls host 0:0 dir6' % fs_type)
|
||||
assert('0123456789abcdef00/' in output)
|
||||
assert('0123456789abcdef13/' in output)
|
||||
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 dir6/0123456789abcdef13/.' % fs_type)
|
||||
assert('./' in output)
|
||||
assert('../' in output)
|
||||
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 dir6/0123456789abcdef13/..' % fs_type)
|
||||
assert('0123456789abcdef00/' in output)
|
||||
assert('0123456789abcdef13/' in output)
|
109
test/py/tests/test_fs/test_unlink.py
Normal file
109
test/py/tests/test_fs/test_unlink.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018, Linaro Limited
|
||||
# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
|
||||
#
|
||||
# U-Boot File System:unlink Test
|
||||
|
||||
"""
|
||||
This test verifies unlink operation (deleting a file or a directory)
|
||||
on file system.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
class TestUnlink(object):
|
||||
def test_unlink1(self, u_boot_console, fs_obj_unlink):
|
||||
"""
|
||||
Test Case 1 - delete a file
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_unlink
|
||||
with u_boot_console.log.section('Test Case 1 - unlink (file)'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%srm host 0:0 dir1/file1' % fs_type,
|
||||
'%sls host 0:0 dir1/file1' % fs_type])
|
||||
assert('' == ''.join(output))
|
||||
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 dir1/' % fs_type)
|
||||
assert(not 'file1' in output)
|
||||
assert('file2' in output)
|
||||
|
||||
def test_unlink2(self, u_boot_console, fs_obj_unlink):
|
||||
"""
|
||||
Test Case 2 - delete many files
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_unlink
|
||||
with u_boot_console.log.section('Test Case 2 - unlink (many)'):
|
||||
output = u_boot_console.run_command('host bind 0 %s' % fs_img)
|
||||
|
||||
for i in range(0, 20):
|
||||
output = u_boot_console.run_command_list([
|
||||
'%srm host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i),
|
||||
'%sls host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i)])
|
||||
assert('' == ''.join(output))
|
||||
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 dir2' % fs_type)
|
||||
assert('0 file(s), 2 dir(s)' in output)
|
||||
|
||||
def test_unlink3(self, u_boot_console, fs_obj_unlink):
|
||||
"""
|
||||
Test Case 3 - trying to delete a non-existing file should fail
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_unlink
|
||||
with u_boot_console.log.section('Test Case 3 - unlink (non-existing)'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%srm host 0:0 dir1/nofile' % fs_type])
|
||||
assert('nofile: doesn\'t exist' in ''.join(output))
|
||||
|
||||
def test_unlink4(self, u_boot_console, fs_obj_unlink):
|
||||
"""
|
||||
Test Case 4 - delete an empty directory
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_unlink
|
||||
with u_boot_console.log.section('Test Case 4 - unlink (directory)'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%srm host 0:0 dir4' % fs_type])
|
||||
assert('' == ''.join(output))
|
||||
|
||||
output = u_boot_console.run_command(
|
||||
'%sls host 0:0 /' % fs_type)
|
||||
assert(not 'dir4' in output)
|
||||
|
||||
def test_unlink5(self, u_boot_console, fs_obj_unlink):
|
||||
"""
|
||||
Test Case 5 - trying to deleting a non-empty directory ".."
|
||||
should fail
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_unlink
|
||||
with u_boot_console.log.section('Test Case 5 - unlink ("non-empty directory")'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%srm host 0:0 dir5' % fs_type])
|
||||
assert('directory is not empty' in ''.join(output))
|
||||
|
||||
def test_unlink6(self, u_boot_console, fs_obj_unlink):
|
||||
"""
|
||||
Test Case 6 - trying to deleting a "." should fail
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_unlink
|
||||
with u_boot_console.log.section('Test Case 6 - unlink (".")'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%srm host 0:0 dir5/.' % fs_type])
|
||||
assert('directory is not empty' in ''.join(output))
|
||||
|
||||
def test_unlink7(self, u_boot_console, fs_obj_unlink):
|
||||
"""
|
||||
Test Case 7 - trying to deleting a ".." should fail
|
||||
"""
|
||||
fs_type,fs_img = fs_obj_unlink
|
||||
with u_boot_console.log.section('Test Case 7 - unlink ("..")'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % fs_img,
|
||||
'%srm host 0:0 dir5/..' % fs_type])
|
||||
assert('directory is not empty' in ''.join(output))
|
543
test/unicode_ut.c
Normal file
543
test/unicode_ut.c
Normal file
|
@ -0,0 +1,543 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Unit tests for Unicode functions
|
||||
*
|
||||
* Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <charset.h>
|
||||
#include <command.h>
|
||||
#include <errno.h>
|
||||
#include <test/test.h>
|
||||
#include <test/suites.h>
|
||||
#include <test/ut.h>
|
||||
|
||||
/* Linker list entry for a Unicode test */
|
||||
#define UNICODE_TEST(_name) UNIT_TEST(_name, 0, unicode_test)
|
||||
|
||||
/* Constants c1-c4 and d1-d4 encode the same letters */
|
||||
|
||||
/* Six characters translating to one utf-8 byte each. */
|
||||
static const u16 c1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00};
|
||||
/* One character translating to two utf-8 bytes */
|
||||
static const u16 c2[] = {0x6b, 0x61, 0x66, 0x62, 0xe1, 0x74, 0x75, 0x72, 0x00};
|
||||
/* Three characters translating to three utf-8 bytes each */
|
||||
static const u16 c3[] = {0x6f5c, 0x6c34, 0x8266, 0x00};
|
||||
/* Three letters translating to four utf-8 bytes each */
|
||||
static const u16 c4[] = {0xd801, 0xdc8d, 0xd801, 0xdc96, 0xd801, 0xdc87,
|
||||
0x0000};
|
||||
|
||||
/* Illegal utf-16 strings */
|
||||
static const u16 i1[] = {0x69, 0x31, 0xdc87, 0x6c, 0x00};
|
||||
static const u16 i2[] = {0x69, 0x32, 0xd801, 0xd801, 0x6c, 0x00};
|
||||
static const u16 i3[] = {0x69, 0x33, 0xd801, 0x00};
|
||||
|
||||
/* Six characters translating to one utf-16 word each. */
|
||||
static const char d1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00};
|
||||
/* Eight characters translating to one utf-16 word each */
|
||||
static const char d2[] = {0x6b, 0x61, 0x66, 0x62, 0xc3, 0xa1, 0x74, 0x75,
|
||||
0x72, 0x00};
|
||||
/* Three characters translating to one utf-16 word each */
|
||||
static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89,
|
||||
0xa6, 0x00};
|
||||
/* Three letters translating to two utf-16 word each */
|
||||
static const char d4[] = {0xf0, 0x90, 0x92, 0x8d, 0xf0, 0x90, 0x92, 0x96,
|
||||
0xf0, 0x90, 0x92, 0x87, 0x00};
|
||||
|
||||
/* Illegal utf-8 strings */
|
||||
static const char j1[] = {0x6a, 0x31, 0xa1, 0x6c, 0x00};
|
||||
static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00};
|
||||
static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00};
|
||||
|
||||
/* U-Boot uses UTF-16 strings in the EFI context only. */
|
||||
#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
|
||||
static int ut_string16(struct unit_test_state *uts)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
/* Test length and precision */
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
sprintf(buf, "%8.6ls", c2);
|
||||
ut_asserteq(' ', buf[1]);
|
||||
ut_assert(!strncmp(&buf[2], d2, 7));
|
||||
ut_assert(!buf[9]);
|
||||
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
sprintf(buf, "%8.6ls", c4);
|
||||
ut_asserteq(' ', buf[4]);
|
||||
ut_assert(!strncmp(&buf[5], d4, 12));
|
||||
ut_assert(!buf[17]);
|
||||
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
sprintf(buf, "%-8.2ls", c4);
|
||||
ut_asserteq(' ', buf[8]);
|
||||
ut_assert(!strncmp(buf, d4, 8));
|
||||
ut_assert(!buf[14]);
|
||||
|
||||
/* Test handling of illegal utf-16 sequences */
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
sprintf(buf, "%ls", i1);
|
||||
ut_asserteq_str("i1?l", buf);
|
||||
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
sprintf(buf, "%ls", i2);
|
||||
ut_asserteq_str("i2?l", buf);
|
||||
|
||||
memset(buf, 0xff, sizeof(buf));
|
||||
sprintf(buf, "%ls", i3);
|
||||
ut_asserteq_str("i3?", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_string16);
|
||||
#endif
|
||||
|
||||
static int ut_utf8_get(struct unit_test_state *uts)
|
||||
{
|
||||
const char *s;
|
||||
s32 code;
|
||||
int i;
|
||||
|
||||
/* Check characters less than 0x800 */
|
||||
s = d2;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
code = utf8_get((const char **)&s);
|
||||
/* c2 is the utf-8 encoding of d2 */
|
||||
ut_asserteq(c2[i], code);
|
||||
if (!code)
|
||||
break;
|
||||
}
|
||||
ut_asserteq_ptr(s, d2 + 9)
|
||||
|
||||
/* Check characters less than 0x10000 */
|
||||
s = d3;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
code = utf8_get((const char **)&s);
|
||||
/* c3 is the utf-8 encoding of d3 */
|
||||
ut_asserteq(c3[i], code);
|
||||
if (!code)
|
||||
break;
|
||||
}
|
||||
ut_asserteq_ptr(s, d3 + 9)
|
||||
|
||||
/* Check character greater 0xffff */
|
||||
s = d4;
|
||||
code = utf8_get((const char **)&s);
|
||||
ut_asserteq(0x0001048d, code);
|
||||
ut_asserteq_ptr(s, d4 + 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf8_get);
|
||||
|
||||
static int ut_utf8_put(struct unit_test_state *uts)
|
||||
{
|
||||
char buffer[8] = { 0, };
|
||||
char *pos;
|
||||
|
||||
/* Commercial at, translates to one character */
|
||||
pos = buffer;
|
||||
ut_assert(!utf8_put('@', &pos))
|
||||
ut_asserteq(1, pos - buffer);
|
||||
ut_asserteq('@', buffer[0]);
|
||||
ut_assert(!buffer[1]);
|
||||
|
||||
/* Latin letter G with acute, translates to two charactes */
|
||||
pos = buffer;
|
||||
ut_assert(!utf8_put(0x1f4, &pos));
|
||||
ut_asserteq(2, pos - buffer);
|
||||
ut_asserteq_str("\xc7\xb4", buffer);
|
||||
|
||||
/* Tagalog letter i, translates to three characters */
|
||||
pos = buffer;
|
||||
ut_assert(!utf8_put(0x1701, &pos));
|
||||
ut_asserteq(3, pos - buffer);
|
||||
ut_asserteq_str("\xe1\x9c\x81", buffer);
|
||||
|
||||
/* Hamster face, translates to four characters */
|
||||
pos = buffer;
|
||||
ut_assert(!utf8_put(0x1f439, &pos));
|
||||
ut_asserteq(4, pos - buffer);
|
||||
ut_asserteq_str("\xf0\x9f\x90\xb9", buffer);
|
||||
|
||||
/* Illegal code */
|
||||
pos = buffer;
|
||||
ut_asserteq(-1, utf8_put(0xd888, &pos));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf8_put);
|
||||
|
||||
static int ut_utf8_utf16_strlen(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq(6, utf8_utf16_strlen(d1));
|
||||
ut_asserteq(8, utf8_utf16_strlen(d2));
|
||||
ut_asserteq(3, utf8_utf16_strlen(d3));
|
||||
ut_asserteq(6, utf8_utf16_strlen(d4));
|
||||
|
||||
/* illegal utf-8 sequences */
|
||||
ut_asserteq(4, utf8_utf16_strlen(j1));
|
||||
ut_asserteq(4, utf8_utf16_strlen(j2));
|
||||
ut_asserteq(3, utf8_utf16_strlen(j3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf8_utf16_strlen);
|
||||
|
||||
static int ut_utf8_utf16_strnlen(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq(3, utf8_utf16_strnlen(d1, 3));
|
||||
ut_asserteq(6, utf8_utf16_strnlen(d1, 13));
|
||||
ut_asserteq(6, utf8_utf16_strnlen(d2, 6));
|
||||
ut_asserteq(2, utf8_utf16_strnlen(d3, 2));
|
||||
ut_asserteq(4, utf8_utf16_strnlen(d4, 2));
|
||||
ut_asserteq(6, utf8_utf16_strnlen(d4, 3));
|
||||
|
||||
/* illegal utf-8 sequences */
|
||||
ut_asserteq(4, utf8_utf16_strnlen(j1, 16));
|
||||
ut_asserteq(4, utf8_utf16_strnlen(j2, 16));
|
||||
ut_asserteq(3, utf8_utf16_strnlen(j3, 16));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf8_utf16_strnlen);
|
||||
|
||||
/**
|
||||
* ut_u16_strcmp() - Compare to u16 strings.
|
||||
*
|
||||
* @a1: first string
|
||||
* @a2: second string
|
||||
* @count: number of u16 to compare
|
||||
* Return: -1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2
|
||||
*/
|
||||
static int ut_u16_strcmp(const u16 *a1, const u16 *a2, size_t count)
|
||||
{
|
||||
for (; (*a1 || *a2) && count; ++a1, ++a2, --count) {
|
||||
if (*a1 < *a2)
|
||||
return -1;
|
||||
if (*a1 > *a2)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ut_utf8_utf16_strcpy(struct unit_test_state *uts)
|
||||
{
|
||||
u16 buf[16];
|
||||
u16 *pos;
|
||||
|
||||
pos = buf;
|
||||
utf8_utf16_strcpy(&pos, d1);
|
||||
ut_asserteq(6, pos - buf);
|
||||
ut_assert(!ut_u16_strcmp(buf, c1, SIZE_MAX));
|
||||
|
||||
pos = buf;
|
||||
utf8_utf16_strcpy(&pos, d2);
|
||||
ut_asserteq(8, pos - buf);
|
||||
ut_assert(!ut_u16_strcmp(buf, c2, SIZE_MAX));
|
||||
|
||||
pos = buf;
|
||||
utf8_utf16_strcpy(&pos, d3);
|
||||
ut_asserteq(3, pos - buf);
|
||||
ut_assert(!ut_u16_strcmp(buf, c3, SIZE_MAX));
|
||||
|
||||
pos = buf;
|
||||
utf8_utf16_strcpy(&pos, d4);
|
||||
ut_asserteq(6, pos - buf);
|
||||
ut_assert(!ut_u16_strcmp(buf, c4, SIZE_MAX));
|
||||
|
||||
/* Illegal utf-8 strings */
|
||||
pos = buf;
|
||||
utf8_utf16_strcpy(&pos, j1);
|
||||
ut_asserteq(4, pos - buf);
|
||||
ut_assert(!ut_u16_strcmp(buf, L"j1?l", SIZE_MAX));
|
||||
|
||||
pos = buf;
|
||||
utf8_utf16_strcpy(&pos, j2);
|
||||
ut_asserteq(4, pos - buf);
|
||||
ut_assert(!ut_u16_strcmp(buf, L"j2?l", SIZE_MAX));
|
||||
|
||||
pos = buf;
|
||||
utf8_utf16_strcpy(&pos, j3);
|
||||
ut_asserteq(3, pos - buf);
|
||||
ut_assert(!ut_u16_strcmp(buf, L"j3?", SIZE_MAX));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf8_utf16_strcpy);
|
||||
|
||||
int ut_utf8_utf16_strncpy(struct unit_test_state *uts)
|
||||
{
|
||||
u16 buf[16];
|
||||
u16 *pos;
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf8_utf16_strncpy(&pos, d1, 4);
|
||||
ut_asserteq(4, pos - buf);
|
||||
ut_assert(!buf[4]);
|
||||
ut_assert(!ut_u16_strcmp(buf, c1, 4));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf8_utf16_strncpy(&pos, d2, 10);
|
||||
ut_asserteq(8, pos - buf);
|
||||
ut_assert(buf[4]);
|
||||
ut_assert(!ut_u16_strcmp(buf, c2, SIZE_MAX));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf8_utf16_strncpy(&pos, d3, 2);
|
||||
ut_asserteq(2, pos - buf);
|
||||
ut_assert(!buf[2]);
|
||||
ut_assert(!ut_u16_strcmp(buf, c3, 2));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf8_utf16_strncpy(&pos, d4, 2);
|
||||
ut_asserteq(4, pos - buf);
|
||||
ut_assert(!buf[4]);
|
||||
ut_assert(!ut_u16_strcmp(buf, c4, 4));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf8_utf16_strncpy(&pos, d4, 10);
|
||||
ut_asserteq(6, pos - buf);
|
||||
ut_assert(buf[5]);
|
||||
ut_assert(!ut_u16_strcmp(buf, c4, SIZE_MAX));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf8_utf16_strncpy);
|
||||
|
||||
static int ut_utf16_get(struct unit_test_state *uts)
|
||||
{
|
||||
const u16 *s;
|
||||
s32 code;
|
||||
int i;
|
||||
|
||||
/* Check characters less than 0x10000 */
|
||||
s = c2;
|
||||
for (i = 0; i < 9; ++i) {
|
||||
code = utf16_get((const u16 **)&s);
|
||||
ut_asserteq(c2[i], code);
|
||||
if (!code)
|
||||
break;
|
||||
}
|
||||
ut_asserteq_ptr(c2 + 8, s);
|
||||
|
||||
/* Check character greater 0xffff */
|
||||
s = c4;
|
||||
code = utf16_get((const u16 **)&s);
|
||||
ut_asserteq(0x0001048d, code);
|
||||
ut_asserteq_ptr(c4 + 2, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf16_get);
|
||||
|
||||
static int ut_utf16_put(struct unit_test_state *uts)
|
||||
{
|
||||
u16 buffer[4] = { 0, };
|
||||
u16 *pos;
|
||||
|
||||
/* Commercial at, translates to one word */
|
||||
pos = buffer;
|
||||
ut_assert(!utf16_put('@', &pos));
|
||||
ut_asserteq(1, pos - buffer);
|
||||
ut_asserteq((u16)'@', buffer[0]);
|
||||
ut_assert(!buffer[1]);
|
||||
|
||||
/* Hamster face, translates to two words */
|
||||
pos = buffer;
|
||||
ut_assert(!utf16_put(0x1f439, &pos));
|
||||
ut_asserteq(2, pos - buffer);
|
||||
ut_asserteq((u16)0xd83d, buffer[0]);
|
||||
ut_asserteq((u16)0xdc39, buffer[1]);
|
||||
ut_assert(!buffer[2]);
|
||||
|
||||
/* Illegal code */
|
||||
pos = buffer;
|
||||
ut_asserteq(-1, utf16_put(0xd888, &pos));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf16_put);
|
||||
|
||||
int ut_utf16_strnlen(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq(3, utf16_strnlen(c1, 3));
|
||||
ut_asserteq(6, utf16_strnlen(c1, 13));
|
||||
ut_asserteq(6, utf16_strnlen(c2, 6));
|
||||
ut_asserteq(2, utf16_strnlen(c3, 2));
|
||||
ut_asserteq(2, utf16_strnlen(c4, 2));
|
||||
ut_asserteq(3, utf16_strnlen(c4, 3));
|
||||
|
||||
/* illegal utf-16 word sequences */
|
||||
ut_asserteq(4, utf16_strnlen(i1, 16));
|
||||
ut_asserteq(4, utf16_strnlen(i2, 16));
|
||||
ut_asserteq(3, utf16_strnlen(i3, 16));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf16_strnlen);
|
||||
|
||||
int ut_utf16_utf8_strlen(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq(6, utf16_utf8_strlen(c1));
|
||||
ut_asserteq(9, utf16_utf8_strlen(c2));
|
||||
ut_asserteq(9, utf16_utf8_strlen(c3));
|
||||
ut_asserteq(12, utf16_utf8_strlen(c4));
|
||||
|
||||
/* illegal utf-16 word sequences */
|
||||
ut_asserteq(4, utf16_utf8_strlen(i1));
|
||||
ut_asserteq(4, utf16_utf8_strlen(i2));
|
||||
ut_asserteq(3, utf16_utf8_strlen(i3));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf16_utf8_strlen);
|
||||
|
||||
int ut_utf16_utf8_strnlen(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq(3, utf16_utf8_strnlen(c1, 3));
|
||||
ut_asserteq(6, utf16_utf8_strnlen(c1, 13));
|
||||
ut_asserteq(7, utf16_utf8_strnlen(c2, 6));
|
||||
ut_asserteq(6, utf16_utf8_strnlen(c3, 2));
|
||||
ut_asserteq(8, utf16_utf8_strnlen(c4, 2));
|
||||
ut_asserteq(12, utf16_utf8_strnlen(c4, 3));
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf16_utf8_strnlen);
|
||||
|
||||
int ut_utf16_utf8_strcpy(struct unit_test_state *uts)
|
||||
{
|
||||
char buf[16];
|
||||
char *pos;
|
||||
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, c1);
|
||||
ut_asserteq(6, pos - buf);
|
||||
ut_asserteq_str(d1, buf);
|
||||
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, c2);
|
||||
ut_asserteq(9, pos - buf);
|
||||
ut_asserteq_str(d2, buf);
|
||||
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, c3);
|
||||
ut_asserteq(9, pos - buf);
|
||||
ut_asserteq_str(d3, buf);
|
||||
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, c4);
|
||||
ut_asserteq(12, pos - buf);
|
||||
ut_asserteq_str(d4, buf);
|
||||
|
||||
/* Illegal utf-16 strings */
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, i1);
|
||||
ut_asserteq(4, pos - buf);
|
||||
ut_asserteq_str("i1?l", buf);
|
||||
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, i2);
|
||||
ut_asserteq(4, pos - buf);
|
||||
ut_asserteq_str("i2?l", buf);
|
||||
|
||||
pos = buf;
|
||||
utf16_utf8_strcpy(&pos, i3);
|
||||
ut_asserteq(3, pos - buf);
|
||||
ut_asserteq_str("i3?", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf16_utf8_strcpy);
|
||||
|
||||
int ut_utf16_utf8_strncpy(struct unit_test_state *uts)
|
||||
{
|
||||
char buf[16];
|
||||
char *pos;
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf16_utf8_strncpy(&pos, c1, 4);
|
||||
ut_asserteq(4, pos - buf);
|
||||
ut_assert(!buf[4]);
|
||||
ut_assert(!strncmp(buf, d1, 4));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf16_utf8_strncpy(&pos, c2, 10);
|
||||
ut_asserteq(9, pos - buf);
|
||||
ut_assert(buf[4]);
|
||||
ut_assert(!strncmp(buf, d2, SIZE_MAX));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf16_utf8_strncpy(&pos, c3, 2);
|
||||
ut_asserteq(6, pos - buf);
|
||||
ut_assert(!buf[6]);
|
||||
ut_assert(!strncmp(buf, d3, 6));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf16_utf8_strncpy(&pos, c4, 2);
|
||||
ut_asserteq(8, pos - buf);
|
||||
ut_assert(!buf[8]);
|
||||
ut_assert(!strncmp(buf, d4, 8));
|
||||
|
||||
pos = buf;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
utf16_utf8_strncpy(&pos, c4, 10);
|
||||
ut_asserteq(12, pos - buf);
|
||||
ut_assert(buf[5]);
|
||||
ut_assert(!strncmp(buf, d4, SIZE_MAX));
|
||||
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf16_utf8_strncpy);
|
||||
|
||||
int ut_utf_to_lower(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq('@', utf_to_lower('@'));
|
||||
ut_asserteq('a', utf_to_lower('A'));
|
||||
ut_asserteq('z', utf_to_lower('Z'));
|
||||
ut_asserteq('[', utf_to_lower('['));
|
||||
ut_asserteq('m', utf_to_lower('m'));
|
||||
/* Latin letter O with diaresis (umlaut) */
|
||||
ut_asserteq(0x00f6, utf_to_lower(0x00d6));
|
||||
#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
|
||||
/* Cyrillic letter I*/
|
||||
ut_asserteq(0x0438, utf_to_lower(0x0418));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf_to_lower);
|
||||
|
||||
int ut_utf_to_upper(struct unit_test_state *uts)
|
||||
{
|
||||
ut_asserteq('`', utf_to_upper('`'));
|
||||
ut_asserteq('A', utf_to_upper('a'));
|
||||
ut_asserteq('Z', utf_to_upper('z'));
|
||||
ut_asserteq('{', utf_to_upper('{'));
|
||||
ut_asserteq('M', utf_to_upper('M'));
|
||||
/* Latin letter O with diaresis (umlaut) */
|
||||
ut_asserteq(0x00d6, utf_to_upper(0x00f6));
|
||||
#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
|
||||
/* Cyrillic letter I */
|
||||
ut_asserteq(0x0418, utf_to_upper(0x0438));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
UNICODE_TEST(ut_utf_to_upper);
|
||||
|
||||
int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test);
|
||||
const int n_ents = ll_entry_count(struct unit_test, unicode_test);
|
||||
|
||||
return cmd_ut_category("Unicode", tests, n_ents, argc, argv);
|
||||
}
|
Loading…
Add table
Reference in a new issue