summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig2
-rw-r--r--common/autoboot.c3
-rw-r--r--common/bloblist.c85
-rw-r--r--common/board_f.c17
-rw-r--r--common/button_cmd.c2
-rw-r--r--common/cli.c4
-rw-r--r--common/cli_readline.c38
-rw-r--r--common/dlmalloc.c154
-rw-r--r--common/hash.c8
-rw-r--r--common/log.c5
-rw-r--r--common/mcheck_core.inc.h304
-rw-r--r--common/spl/spl.c3
-rw-r--r--common/spl/spl_fit.c7
-rw-r--r--common/usb.c70
-rw-r--r--common/usb_kbd.c59
15 files changed, 687 insertions, 74 deletions
diff --git a/common/Kconfig b/common/Kconfig
index 0283701f1d0..5e3070e9253 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -231,7 +231,7 @@ config PRE_CON_BUF_ADDR
default 0x2f000000 if ARCH_SUNXI && MACH_SUN9I
default 0x4f000000 if ARCH_SUNXI && !MACH_SUN9I
default 0x0f000000 if ROCKCHIP_RK3288
- default 0x0f200000 if ROCKCHIP_RK3399
+ default 0x0f200000 if ROCKCHIP_RK3399 || ROCKCHIP_RK3328
help
This sets the start address of the pre-console buffer. This must
be in available memory and is accessed before relocation and
diff --git a/common/autoboot.c b/common/autoboot.c
index 5d331991c19..6f0aeae6bf3 100644
--- a/common/autoboot.c
+++ b/common/autoboot.c
@@ -167,6 +167,9 @@ static int passwd_abort_sha256(uint64_t etime)
sha_env_str = AUTOBOOT_STOP_STR_SHA256;
presskey = malloc_cache_aligned(DELAY_STOP_STR_MAX_LENGTH);
+ if (!presskey)
+ return -ENOMEM;
+
c = strstr(sha_env_str, ":");
if (c && (c - sha_env_str < DELAY_STOP_STR_MAX_LENGTH)) {
/* preload presskey with salt */
diff --git a/common/bloblist.c b/common/bloblist.c
index 2d373910b6d..ad06d7a1795 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -384,7 +384,7 @@ int bloblist_check(ulong addr, uint size)
return log_msg_ret("Bad magic", -ENOENT);
if (hdr->version != BLOBLIST_VERSION)
return log_msg_ret("Bad version", -EPROTONOSUPPORT);
- if (!hdr->total_size || (size && hdr->total_size != size))
+ if (!hdr->total_size || (size && hdr->total_size > size))
return log_msg_ret("Bad total size", -EFBIG);
if (hdr->used_size > hdr->total_size)
return log_msg_ret("Bad used size", -ENOENT);
@@ -472,13 +472,28 @@ void bloblist_show_list(void)
}
}
-void bloblist_reloc(void *to, uint to_size, void *from, uint from_size)
+int bloblist_reloc(void *to, uint to_size)
{
struct bloblist_hdr *hdr;
- memcpy(to, from, from_size);
+ if (to_size < gd->bloblist->total_size)
+ return -ENOSPC;
+
+ memcpy(to, gd->bloblist, gd->bloblist->total_size);
hdr = to;
hdr->total_size = to_size;
+ gd->bloblist = to;
+
+ return 0;
+}
+
+/*
+ * Weak default function for getting bloblist from boot args.
+ */
+int __weak xferlist_from_boot_arg(ulong __always_unused addr,
+ ulong __always_unused size)
+{
+ return -ENOENT;
}
int bloblist_init(void)
@@ -486,32 +501,43 @@ int bloblist_init(void)
bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED);
int ret = -ENOENT;
ulong addr, size;
- bool expected;
-
- /**
- * We don't expect to find an existing bloblist in the first phase of
- * U-Boot that runs. Also we have no way to receive the address of an
- * allocated bloblist from a previous stage, so it must be at a fixed
+ /*
+ * If U-Boot is not in the first phase, an existing bloblist must be
+ * at a fixed address.
+ */
+ bool from_addr = fixed && !u_boot_first_phase();
+ /*
+ * If U-Boot is in the first phase that an arch custom routine should
+ * install the bloblist passed from previous loader to this fixed
* address.
*/
- expected = fixed && !u_boot_first_phase();
+ bool from_boot_arg = fixed && u_boot_first_phase();
+
if (spl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST))
- expected = false;
+ from_addr = false;
if (fixed)
addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED,
CONFIG_BLOBLIST_ADDR);
size = CONFIG_BLOBLIST_SIZE;
- if (expected) {
+
+ if (from_boot_arg)
+ ret = xferlist_from_boot_arg(addr, size);
+ else if (from_addr)
ret = bloblist_check(addr, size);
- if (ret) {
- log_warning("Expected bloblist at %lx not found (err=%d)\n",
- addr, ret);
- } else {
- /* Get the real size, if it is not what we expected */
- size = gd->bloblist->total_size;
- }
- }
+
+ if (ret)
+ log_warning("Bloblist at %lx not found (err=%d)\n",
+ addr, ret);
+ else
+ /* Get the real size */
+ size = gd->bloblist->total_size;
+
if (ret) {
+ /*
+ * If we don't have a bloblist from a fixed address, or the one
+ * in the fixed address is not valid. we must allocate the
+ * memory for it now.
+ */
if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) {
void *ptr = memalign(BLOBLIST_ALIGN, size);
@@ -519,7 +545,8 @@ int bloblist_init(void)
return log_msg_ret("alloc", -ENOMEM);
addr = map_to_sysmem(ptr);
} else if (!fixed) {
- return log_msg_ret("!fixed", ret);
+ return log_msg_ret("BLOBLIST_FIXED is not enabled",
+ ret);
}
log_debug("Creating new bloblist size %lx at %lx\n", size,
addr);
@@ -532,6 +559,11 @@ int bloblist_init(void)
return log_msg_ret("ini", ret);
gd->flags |= GD_FLG_BLOBLIST_READY;
+#ifdef DEBUG
+ bloblist_show_stats();
+ bloblist_show_list();
+#endif
+
return 0;
}
@@ -542,3 +574,14 @@ int bloblist_maybe_init(void)
return 0;
}
+
+int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig)
+{
+ if (rzero || rsig != (BLOBLIST_MAGIC | BLOBLIST_REGCONV_VER) ||
+ rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) {
+ gd->bloblist = NULL; /* Reset the gd bloblist pointer */
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/common/board_f.c b/common/board_f.c
index 442b8349d08..039d6d712d0 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -282,7 +282,9 @@ static int init_func_i2c(void)
static int setup_mon_len(void)
{
-#if defined(__ARM__) || defined(__MICROBLAZE__)
+#if defined(CONFIG_ARCH_NEXELL)
+ gd->mon_len = (ulong)__bss_end - (ulong)__image_copy_start;
+#elif defined(__ARM__) || defined(__MICROBLAZE__)
gd->mon_len = (ulong)__bss_end - (ulong)_start;
#elif defined(CONFIG_SANDBOX) && !defined(__riscv)
gd->mon_len = (ulong)_end - (ulong)_init;
@@ -706,19 +708,17 @@ static int reloc_bloblist(void)
return 0;
}
if (gd->new_bloblist) {
- int size = CONFIG_BLOBLIST_SIZE;
-
debug("Copying bloblist from %p to %p, size %x\n",
- gd->bloblist, gd->new_bloblist, size);
- bloblist_reloc(gd->new_bloblist, CONFIG_BLOBLIST_SIZE_RELOC,
- gd->bloblist, size);
- gd->bloblist = gd->new_bloblist;
+ gd->bloblist, gd->new_bloblist, gd->bloblist->total_size);
+ return bloblist_reloc(gd->new_bloblist,
+ CONFIG_BLOBLIST_SIZE_RELOC);
}
#endif
return 0;
}
+void mcheck_on_ramrelocation(size_t offset);
static int setup_reloc(void)
{
if (!(gd->flags & GD_FLG_SKIP_RELOC)) {
@@ -744,6 +744,9 @@ static int setup_reloc(void)
if (gd->flags & GD_FLG_SKIP_RELOC) {
debug("Skipping relocation due to flag\n");
} else {
+#ifdef MCHECK_HEAP_PROTECTION
+ mcheck_on_ramrelocation(gd->reloc_off);
+#endif
debug("Relocation Offset is: %08lx\n", gd->reloc_off);
debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
diff --git a/common/button_cmd.c b/common/button_cmd.c
index b6a8434d6f2..8642c26735c 100644
--- a/common/button_cmd.c
+++ b/common/button_cmd.c
@@ -33,7 +33,7 @@ struct button_cmd {
static int get_button_cmd(int n, struct button_cmd *cmd)
{
const char *cmd_str;
- struct udevice *btn;
+ struct udevice *btn = NULL;
char buf[24];
snprintf(buf, sizeof(buf), "button_cmd_%d_name", n);
diff --git a/common/cli.c b/common/cli.c
index a34938294ec..1c33daf1149 100644
--- a/common/cli.c
+++ b/common/cli.c
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) "cli: %s: " fmt, __func__
#include <common.h>
+#include <ansi.h>
#include <bootstage.h>
#include <cli.h>
#include <cli_hush.h>
@@ -336,4 +337,7 @@ void cli_init(void)
#if defined(CONFIG_HUSH_INIT_VAR)
hush_init_var();
#endif
+
+ if (CONFIG_IS_ENABLED(VIDEO_ANSI))
+ printf(ANSI_CURSOR_SHOW "\n");
}
diff --git a/common/cli_readline.c b/common/cli_readline.c
index 2507be22952..cf4339d0e50 100644
--- a/common/cli_readline.c
+++ b/common/cli_readline.c
@@ -86,6 +86,9 @@ static int hist_add_idx;
static int hist_cur = -1;
static unsigned hist_num;
+#ifndef CONFIG_CMD_HISTORY_USE_CALLOC
+static char hist_data[HIST_MAX][HIST_SIZE + 1];
+#endif
static char *hist_list[HIST_MAX];
#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
@@ -100,20 +103,26 @@ static void getcmd_putchars(int count, int ch)
static int hist_init(void)
{
- unsigned char *hist;
int i;
- hist_max = 0;
- hist_add_idx = 0;
- hist_cur = -1;
- hist_num = 0;
-
- hist = calloc(HIST_MAX, HIST_SIZE + 1);
+#ifndef CONFIG_CMD_HISTORY_USE_CALLOC
+ for (i = 0; i < HIST_MAX; i++) {
+ hist_list[i] = hist_data[i];
+ hist_list[i][0] = '\0';
+ }
+#else
+ unsigned char *hist = calloc(HIST_MAX, HIST_SIZE + 1);
if (!hist)
- return -ENOMEM;
+ panic("%s: calloc: out of memory!\n", __func__);
for (i = 0; i < HIST_MAX; i++)
hist_list[i] = hist + (i * (HIST_SIZE + 1));
+#endif
+
+ hist_max = 0;
+ hist_add_idx = 0;
+ hist_cur = -1;
+ hist_num = 0;
return 0;
}
@@ -643,10 +652,15 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer,
static int initted;
/*
- * History uses a global array which is not
- * writable until after relocation to RAM.
- * Revert to non-history version if still
- * running from flash.
+ * Say N to CMD_HISTORY_USE_CALLOC will skip runtime
+ * allocation for the history buffer and directly
+ * use an uninitialized static array as the buffer.
+ * Doing this might have better performance and not
+ * increase the binary file's size, as it only marks
+ * the size. However, the array is only writable after
+ * relocation to RAM. If u-boot is running from ROM
+ * all the time, consider say Y to CMD_HISTORY_USE_CALLOC
+ * or disable CMD_HISTORY.
*/
if (IS_ENABLED(CONFIG_CMDLINE_EDITING) && (gd->flags & GD_FLG_RELOC)) {
if (!initted) {
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index de3f04225f4..a0616217d49 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -32,6 +32,21 @@ void malloc_stats();
DECLARE_GLOBAL_DATA_PTR;
+#ifdef MCHECK_HEAP_PROTECTION
+ #define STATIC_IF_MCHECK static
+ #undef MALLOC_COPY
+ #undef MALLOC_ZERO
+static inline void MALLOC_ZERO(void *p, size_t sz) { memset(p, 0, sz); }
+static inline void MALLOC_COPY(void *dest, const void *src, size_t sz) { memcpy(dest, src, sz); }
+#else
+ #define STATIC_IF_MCHECK
+ #define mALLOc_impl mALLOc
+ #define fREe_impl fREe
+ #define rEALLOc_impl rEALLOc
+ #define mEMALIGn_impl mEMALIGn
+ #define cALLOc_impl cALLOc
+#endif
+
/*
Emulation of sbrk for WIN32
All code within the ifdef WIN32 is untested by me.
@@ -1270,10 +1285,11 @@ static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
*/
+STATIC_IF_MCHECK
#if __STD_C
-Void_t* mALLOc(size_t bytes)
+Void_t* mALLOc_impl(size_t bytes)
#else
-Void_t* mALLOc(bytes) size_t bytes;
+Void_t* mALLOc_impl(bytes) size_t bytes;
#endif
{
mchunkptr victim; /* inspected/selected chunk */
@@ -1555,10 +1571,11 @@ Void_t* mALLOc(bytes) size_t bytes;
*/
+STATIC_IF_MCHECK
#if __STD_C
-void fREe(Void_t* mem)
+void fREe_impl(Void_t* mem)
#else
-void fREe(mem) Void_t* mem;
+void fREe_impl(mem) Void_t* mem;
#endif
{
mchunkptr p; /* chunk corresponding to mem */
@@ -1696,10 +1713,11 @@ void fREe(mem) Void_t* mem;
*/
+STATIC_IF_MCHECK
#if __STD_C
-Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+Void_t* rEALLOc_impl(Void_t* oldmem, size_t bytes)
#else
-Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+Void_t* rEALLOc_impl(oldmem, bytes) Void_t* oldmem; size_t bytes;
#endif
{
INTERNAL_SIZE_T nb; /* padded request size */
@@ -1725,7 +1743,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
#ifdef REALLOC_ZERO_BYTES_FREES
if (!bytes) {
- fREe(oldmem);
+ fREe_impl(oldmem);
return NULL;
}
#endif
@@ -1733,7 +1751,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
if ((long)bytes < 0) return NULL;
/* realloc of null is supposed to be same as malloc */
- if (oldmem == NULL) return mALLOc(bytes);
+ if (oldmem == NULL) return mALLOc_impl(bytes);
#if CONFIG_IS_ENABLED(SYS_MALLOC_F)
if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
@@ -1758,7 +1776,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
/* Note the extra SIZE_SZ overhead. */
if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
/* Must alloc, copy, free. */
- newmem = mALLOc(bytes);
+ newmem = mALLOc_impl(bytes);
if (!newmem)
return NULL; /* propagate failure */
MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
@@ -1869,7 +1887,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
/* Must allocate */
- newmem = mALLOc (bytes);
+ newmem = mALLOc_impl (bytes);
if (newmem == NULL) /* propagate failure */
return NULL;
@@ -1886,7 +1904,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
/* Otherwise copy, free, and exit */
MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
- fREe(oldmem);
+ fREe_impl(oldmem);
return newmem;
} else {
VALGRIND_RESIZEINPLACE_BLOCK(oldmem, 0, bytes, SIZE_SZ);
@@ -1905,7 +1923,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
set_inuse_bit_at_offset(remainder, remainder_size);
VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(remainder), remainder_size, SIZE_SZ,
false);
- fREe(chunk2mem(remainder)); /* let free() deal with it */
+ fREe_impl(chunk2mem(remainder)); /* let free() deal with it */
}
else
{
@@ -1939,10 +1957,11 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
*/
+STATIC_IF_MCHECK
#if __STD_C
-Void_t* mEMALIGn(size_t alignment, size_t bytes)
+Void_t* mEMALIGn_impl(size_t alignment, size_t bytes)
#else
-Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+Void_t* mEMALIGn_impl(alignment, bytes) size_t alignment; size_t bytes;
#endif
{
INTERNAL_SIZE_T nb; /* padded request size */
@@ -1965,7 +1984,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
/* If need less alignment than we give anyway, just relay to malloc */
- if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
+ if (alignment <= MALLOC_ALIGNMENT) return mALLOc_impl(bytes);
/* Otherwise, ensure that it is at least a minimum chunk size */
@@ -1974,7 +1993,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
/* Call malloc with worst case padding to hit alignment. */
nb = request2size(bytes);
- m = (char*)(mALLOc(nb + alignment + MINSIZE));
+ m = (char*)(mALLOc_impl(nb + alignment + MINSIZE));
/*
* The attempt to over-allocate (with a size large enough to guarantee the
@@ -1990,7 +2009,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
* Use bytes not nb, since mALLOc internally calls request2size too, and
* each call increases the size to allocate, to account for the header.
*/
- m = (char*)(mALLOc(bytes));
+ m = (char*)(mALLOc_impl(bytes));
/* Aligned -> return it */
if ((((unsigned long)(m)) % alignment) == 0)
return m;
@@ -1998,10 +2017,10 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
* Otherwise, try again, requesting enough extra space to be able to
* acquire alignment.
*/
- fREe(m);
+ fREe_impl(m);
/* Add in extra bytes to match misalignment of unexpanded allocation */
extra = alignment - (((unsigned long)(m)) % alignment);
- m = (char*)(mALLOc(bytes + extra));
+ m = (char*)(mALLOc_impl(bytes + extra));
/*
* m might not be the same as before. Validate that the previous value of
* extra still works for the current value of m.
@@ -2010,7 +2029,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
if (m) {
extra2 = alignment - (((unsigned long)(m)) % alignment);
if (extra2 > extra) {
- fREe(m);
+ fREe_impl(m);
m = NULL;
}
}
@@ -2060,7 +2079,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
set_head(newp, newsize | PREV_INUSE);
set_inuse_bit_at_offset(newp, newsize);
set_head_size(p, leadsize);
- fREe(chunk2mem(p));
+ fREe_impl(chunk2mem(p));
p = newp;
VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(p), bytes, SIZE_SZ, false);
@@ -2078,7 +2097,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
set_head_size(p, nb);
VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(remainder), remainder_size, SIZE_SZ,
false);
- fREe(chunk2mem(remainder));
+ fREe_impl(chunk2mem(remainder));
}
check_inuse_chunk(p);
@@ -2126,10 +2145,11 @@ Void_t* pvALLOc(bytes) size_t bytes;
*/
+STATIC_IF_MCHECK
#if __STD_C
-Void_t* cALLOc(size_t n, size_t elem_size)
+Void_t* cALLOc_impl(size_t n, size_t elem_size)
#else
-Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
+Void_t* cALLOc_impl(n, elem_size) size_t n; size_t elem_size;
#endif
{
mchunkptr p;
@@ -2145,7 +2165,7 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
INTERNAL_SIZE_T oldtopsize = chunksize(top);
#endif
#endif
- Void_t* mem = mALLOc (sz);
+ Void_t* mem = mALLOc_impl (sz);
if ((long)n < 0) return NULL;
@@ -2205,6 +2225,90 @@ void cfree(mem) Void_t *mem;
#endif
+#ifdef MCHECK_HEAP_PROTECTION
+ #include "mcheck_core.inc.h"
+ #if !__STD_C
+ #error "must have __STD_C"
+ #endif
+
+Void_t *mALLOc(size_t bytes)
+{
+ mcheck_pedantic_prehook();
+ size_t fullsz = mcheck_alloc_prehook(bytes);
+ void *p = mALLOc_impl(fullsz);
+
+ if (!p)
+ return p;
+ return mcheck_alloc_posthook(p, bytes);
+}
+
+void fREe(Void_t *mem) { fREe_impl(mcheck_free_prehook(mem)); }
+
+Void_t *rEALLOc(Void_t *oldmem, size_t bytes)
+{
+ mcheck_pedantic_prehook();
+ if (bytes == 0) {
+ if (oldmem)
+ fREe(oldmem);
+ return NULL;
+ }
+
+ if (oldmem == NULL)
+ return mALLOc(bytes);
+
+ void *p = mcheck_reallocfree_prehook(oldmem);
+ size_t newsz = mcheck_alloc_prehook(bytes);
+
+ p = rEALLOc_impl(p, newsz);
+ if (!p)
+ return p;
+ return mcheck_alloc_noclean_posthook(p, bytes);
+}
+
+Void_t *mEMALIGn(size_t alignment, size_t bytes)
+{
+ mcheck_pedantic_prehook();
+ size_t fullsz = mcheck_memalign_prehook(alignment, bytes);
+ void *p = mEMALIGn_impl(alignment, fullsz);
+
+ if (!p)
+ return p;
+ return mcheck_memalign_posthook(alignment, p, bytes);
+}
+
+// pvALLOc, vALLOc - redirect to mEMALIGn, defined here, so they need no wrapping.
+
+Void_t *cALLOc(size_t n, size_t elem_size)
+{
+ mcheck_pedantic_prehook();
+ // NB: here is no overflow check.
+ size_t fullsz = mcheck_alloc_prehook(n * elem_size);
+ void *p = cALLOc_impl(1, fullsz);
+
+ if (!p)
+ return p;
+ return mcheck_alloc_noclean_posthook(p, n * elem_size);
+}
+
+// mcheck API {
+int mcheck_pedantic(mcheck_abortfunc_t f)
+{
+ mcheck_initialize(f, 1);
+ return 0;
+}
+
+int mcheck(mcheck_abortfunc_t f)
+{
+ mcheck_initialize(f, 0);
+ return 0;
+}
+
+void mcheck_check_all(void) { mcheck_pedantic_check(); }
+
+enum mcheck_status mprobe(void *__ptr) { return mcheck_mprobe(__ptr); }
+// mcheck API }
+#endif
+
/*
diff --git a/common/hash.c b/common/hash.c
index e837c56d443..3d6b84de473 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -321,7 +321,8 @@ static struct hash_algo hash_algo[] = {
/* Try to minimize code size for boards that don't want much hashing */
#if CONFIG_IS_ENABLED(SHA256) || IS_ENABLED(CONFIG_CMD_SHA1SUM) || \
CONFIG_IS_ENABLED(CRC32_VERIFY) || IS_ENABLED(CONFIG_CMD_HASH) || \
- CONFIG_IS_ENABLED(SHA384) || CONFIG_IS_ENABLED(SHA512)
+ CONFIG_IS_ENABLED(SHA384) || CONFIG_IS_ENABLED(SHA512) || \
+ IS_ENABLED(CONFIG_CMD_MD5SUM)
#define multi_hash() 1
#else
#define multi_hash() 0
@@ -404,7 +405,8 @@ int hash_block(const char *algo_name, const void *data, unsigned int len,
}
#if !defined(CONFIG_SPL_BUILD) && (defined(CONFIG_CMD_HASH) || \
- defined(CONFIG_CMD_SHA1SUM) || defined(CONFIG_CMD_CRC32))
+ defined(CONFIG_CMD_SHA1SUM) || defined(CONFIG_CMD_CRC32)) || \
+ defined(CONFIG_CMD_MD5SUM)
/**
* store_result: Store the resulting sum to an address or variable
*
@@ -565,7 +567,7 @@ int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp,
/* Try to avoid code bloat when verify is not needed */
#if defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_SHA1SUM_VERIFY) || \
- defined(CONFIG_HASH_VERIFY)
+ defined(CONFIG_MD5SUM_VERIFY) || defined(CONFIG_HASH_VERIFY)
if (flags & HASH_FLAG_VERIFY) {
#else
if (0) {
diff --git a/common/log.c b/common/log.c
index b2de57fcb3b..42d35f04b68 100644
--- a/common/log.c
+++ b/common/log.c
@@ -428,6 +428,11 @@ int log_device_set_enable(struct log_driver *drv, bool enable)
return 0;
}
+void log_fixup_for_gd_move(struct global_data *new_gd)
+{
+ new_gd->log_head.prev->next = &new_gd->log_head;
+}
+
int log_init(void)
{
struct log_driver *drv = ll_entry_start(struct log_driver, log_driver);
diff --git a/common/mcheck_core.inc.h b/common/mcheck_core.inc.h
new file mode 100644
index 00000000000..69021409922
--- /dev/null
+++ b/common/mcheck_core.inc.h
@@ -0,0 +1,304 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Written by Eugene Uriev, based on glibc 2.0 prototype of Mike Haertel.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ * <https://www.gnu.org/licenses/>
+ */
+
+/*
+ * TL;DR: this is a porting of glibc mcheck into U-Boot
+ *
+ * This file contains no entities for external linkage.
+ * So mcheck protection may be used in parallel, e.g. for "malloc_simple(..)" and "malloc(..)".
+ * To do so, the file should be shared/include twice, - without linkage conflicts.
+ * I.e. "core"-part is shared as a source, but not as a binary.
+ * Maybe some optimization here make sense, to engage more binary sharing too.
+ * But, currently I strive to keep it as simple, as possible.
+ * And this, programmers'-only, mode don't pretend to be main.
+ *
+ * This library is aware of U-Boot specific. It's also aware of ARM alignment concerns.
+ * Unlike glibc-clients, U-Boot has limited malloc-usage, and only one thread.
+ * So it's better to make the protection heavier.
+ * Thus overflow canary here is greater, than glibc's one. Underflow canary is bigger too.
+ * U-Boot also allows to use fixed-size heap-registry, instead of double-linked list in glibc.
+ *
+ * Heavy canary allows to catch not only memset(..)-errors,
+ * but overflow/underflow of struct-array access:
+ * {
+ * struct mystruct* p = malloc(sizeof(struct mystruct) * N);
+ * p[-1].field1 = 0;
+ * p[N].field2 = 13;
+ * }
+ * TODO: In order to guarantee full coverage of that kind of errors, a user can add variable-size
+ * canaries here. So pre- and post-canary with size >= reqested_size, could be provided
+ * (with the price of 3x heap-usage). Therefore, it would catch 100% of changes beyond
+ * an array, for index(+1/-1) errors.
+ *
+ * U-Boot is a BL, not an OS with a lib. Activity of the library is set not in runtime,
+ * rather in compile-time, by MCHECK_HEAP_PROTECTION macro. That guarantees that
+ * we haven't missed first malloc.
+ */
+
+/*
+ * Testing
+ * This library had been successfully tested for U-Boot @ ARM SoC chip / 64bits.
+ * Proven for both default and pedantic mode: confirms U-Boot to be clean, and catches
+ * intentional/testing corruptions. Working with malloc_trim is not tested.
+ */
+#ifndef _MCHECKCORE_INC_H
+#define _MCHECKCORE_INC_H 1
+#include "mcheck.h"
+
+#if defined(MCHECK_HEAP_PROTECTION)
+#define mcheck_flood memset
+
+// these are from /dev/random:
+#define MAGICWORD 0x99ccf430fa562a05ULL
+#define MAGICFREE 0x4875e63c0c6fc08eULL
+#define MAGICTAIL 0x918dbcd7df78dcd6ULL
+#define MALLOCFLOOD ((char)0xb6)
+#define FREEFLOOD ((char)0xf5)
+#define PADDINGFLOOD ((char)0x58)
+
+// my normal run demands 4427-6449 chunks:
+#define REGISTRY_SZ 6608
+#define CANARY_DEPTH 2
+
+// avoid problems with BSS at early stage:
+static char mcheck_pedantic_flag __section(".data") = 0;
+static void *mcheck_registry[REGISTRY_SZ] __section(".data") = {0};
+static size_t mcheck_chunk_count __section(".data") = 0;
+static size_t mcheck_chunk_count_max __section(".data") = 0;
+
+typedef unsigned long long mcheck_elem;
+typedef struct {
+ mcheck_elem elems[CANARY_DEPTH];
+} mcheck_canary;
+struct mcheck_hdr {
+ size_t size; /* Exact size requested by user. */
+ size_t aln_skip; /* Ignored bytes, before the mcheck_hdr, to fulfill alignment */
+ mcheck_canary canary; /* Magic number to check header integrity. */
+};
+
+static void mcheck_default_abort(enum mcheck_status status, const void *p)
+{
+ const char *msg;
+
+ switch (status) {
+ case MCHECK_OK:
+ msg = "memory is consistent, library is buggy\n";
+ break;
+ case MCHECK_HEAD:
+ msg = "memory clobbered before allocated block\n";
+ break;
+ case MCHECK_TAIL:
+ msg = "memory clobbered past end of allocated block\n";
+ break;
+ case MCHECK_FREE:
+ msg = "block freed twice\n";
+ break;
+ default:
+ msg = "bogus mcheck_status, library is buggy\n";
+ break;
+ }
+ printf("\n\nmcheck: %p:%s!!! [%zu]\n\n", p, msg, mcheck_chunk_count_max);
+}
+
+static mcheck_abortfunc_t mcheck_abortfunc = &mcheck_default_abort;
+
+static inline size_t allign_size_up(size_t sz, size_t grain)
+{
+ return (sz + grain - 1) & ~(grain - 1);
+}
+
+#define mcheck_allign_customer_size(SZ) allign_size_up(SZ, sizeof(mcheck_elem))
+#define mcheck_evaluate_memalign_prefix_size(ALIGN) allign_size_up(sizeof(struct mcheck_hdr), ALIGN)
+
+static enum mcheck_status mcheck_OnNok(enum mcheck_status status, const void *p)
+{
+ (*mcheck_abortfunc)(status, p);
+ return status;
+}
+
+static enum mcheck_status mcheck_checkhdr(const struct mcheck_hdr *hdr)
+{
+ int i;
+
+ for (i = 0; i < CANARY_DEPTH; ++i)
+ if (hdr->canary.elems[i] == MAGICFREE)
+ return mcheck_OnNok(MCHECK_FREE, hdr + 1);
+
+ for (i = 0; i < CANARY_DEPTH; ++i)
+ if (hdr->canary.elems[i] != MAGICWORD)
+ return mcheck_OnNok(MCHECK_HEAD, hdr + 1);
+
+ const size_t payload_size = hdr->size;
+ const size_t payload_size_aligned = mcheck_allign_customer_size(payload_size);
+ const size_t padd_size = payload_size_aligned - hdr->size;
+
+ const char *payload = (const char *)&hdr[1];
+
+ for (i = 0; i < padd_size; ++i)
+ if (payload[payload_size + i] != PADDINGFLOOD)
+ return mcheck_OnNok(MCHECK_TAIL, hdr + 1);
+
+ const mcheck_canary *tail = (const mcheck_canary *)&payload[payload_size_aligned];
+
+ for (i = 0; i < CANARY_DEPTH; ++i)
+ if (tail->elems[i] != MAGICTAIL)
+ return mcheck_OnNok(MCHECK_TAIL, hdr + 1);
+ return MCHECK_OK;
+}
+
+enum { KEEP_CONTENT = 0, CLEAN_CONTENT, ANY_ALIGNMENT = 1 };
+static void *mcheck_free_helper(void *ptr, int clean_content)
+{
+ if (!ptr)
+ return ptr;
+
+ struct mcheck_hdr *hdr = &((struct mcheck_hdr *)ptr)[-1];
+ int i;
+
+ mcheck_checkhdr(hdr);
+ for (i = 0; i < CANARY_DEPTH; ++i)
+ hdr->canary.elems[i] = MAGICFREE;
+
+ if (clean_content)
+ mcheck_flood(ptr, FREEFLOOD, mcheck_allign_customer_size(hdr->size));
+
+ for (i = 0; i < REGISTRY_SZ; ++i)
+ if (mcheck_registry[i] == hdr) {
+ mcheck_registry[i] = 0;
+ break;
+ }
+
+ --mcheck_chunk_count;
+ return (char *)hdr - hdr->aln_skip;
+}
+
+static void *mcheck_free_prehook(void *ptr) { return mcheck_free_helper(ptr, CLEAN_CONTENT); }
+static void *mcheck_reallocfree_prehook(void *ptr) { return mcheck_free_helper(ptr, KEEP_CONTENT); }
+
+static size_t mcheck_alloc_prehook(size_t sz)
+{
+ sz = mcheck_allign_customer_size(sz);
+ return sizeof(struct mcheck_hdr) + sz + sizeof(mcheck_canary);
+}
+
+static void *mcheck_allocated_helper(void *altoghether_ptr, size_t customer_sz,
+ size_t alignment, int clean_content)
+{
+ const size_t slop = alignment ?
+ mcheck_evaluate_memalign_prefix_size(alignment) - sizeof(struct mcheck_hdr) : 0;
+ struct mcheck_hdr *hdr = (struct mcheck_hdr *)((char *)altoghether_ptr + slop);
+ int i;
+
+ hdr->size = customer_sz;
+ hdr->aln_skip = slop;
+ for (i = 0; i < CANARY_DEPTH; ++i)
+ hdr->canary.elems[i] = MAGICWORD;
+
+ char *payload = (char *)&hdr[1];
+
+ if (clean_content)
+ mcheck_flood(payload, MALLOCFLOOD, customer_sz);
+
+ const size_t customer_size_aligned = mcheck_allign_customer_size(customer_sz);
+
+ mcheck_flood(payload + customer_sz, PADDINGFLOOD, customer_size_aligned - customer_sz);
+
+ mcheck_canary *tail = (mcheck_canary *)&payload[customer_size_aligned];
+
+ for (i = 0; i < CANARY_DEPTH; ++i)
+ tail->elems[i] = MAGICTAIL;
+
+ ++mcheck_chunk_count;
+ if (mcheck_chunk_count > mcheck_chunk_count_max)
+ mcheck_chunk_count_max = mcheck_chunk_count;
+
+ for (i = 0; i < REGISTRY_SZ; ++i)
+ if (!mcheck_registry[i]) {
+ mcheck_registry[i] = hdr;
+ return payload; // normal end
+ }
+
+ static char *overflow_msg = "\n\n\nERROR: mcheck registry overflow, pedantic check would be incomplete!!\n\n\n\n";
+
+ printf("%s", overflow_msg);
+ overflow_msg = "(mcheck registry full)";
+ return payload;
+}
+
+static void *mcheck_alloc_posthook(void *altoghether_ptr, size_t customer_sz)
+{
+ return mcheck_allocated_helper(altoghether_ptr, customer_sz, ANY_ALIGNMENT, CLEAN_CONTENT);
+}
+
+static void *mcheck_alloc_noclean_posthook(void *altoghether_ptr, size_t customer_sz)
+{
+ return mcheck_allocated_helper(altoghether_ptr, customer_sz, ANY_ALIGNMENT, KEEP_CONTENT);
+}
+
+static size_t mcheck_memalign_prehook(size_t alig, size_t sz)
+{
+ return mcheck_evaluate_memalign_prefix_size(alig) + sz + sizeof(mcheck_canary);
+}
+
+static void *mcheck_memalign_posthook(size_t alignment, void *altoghether_ptr, size_t customer_sz)
+{
+ return mcheck_allocated_helper(altoghether_ptr, customer_sz, alignment, CLEAN_CONTENT);
+}
+
+static enum mcheck_status mcheck_mprobe(void *ptr)
+{
+ struct mcheck_hdr *hdr = &((struct mcheck_hdr *)ptr)[-1];
+
+ return mcheck_checkhdr(hdr);
+}
+
+static void mcheck_pedantic_check(void)
+{
+ int i;
+
+ for (i = 0; i < REGISTRY_SZ; ++i)
+ if (mcheck_registry[i])
+ mcheck_checkhdr(mcheck_registry[i]);
+}
+
+static void mcheck_pedantic_prehook(void)
+{
+ if (mcheck_pedantic_flag)
+ mcheck_pedantic_check();
+}
+
+static void mcheck_initialize(mcheck_abortfunc_t new_func, char pedantic_flag)
+{
+ mcheck_abortfunc = (new_func) ? new_func : &mcheck_default_abort;
+ mcheck_pedantic_flag = pedantic_flag;
+}
+
+void mcheck_on_ramrelocation(size_t offset)
+{
+ char *p;
+ int i;
+ // Simple, but inaccurate strategy: drop the pre-reloc heap
+ for (i = 0; i < REGISTRY_SZ; ++i)
+ if ((p = mcheck_registry[i]) != NULL ) {
+ printf("mcheck, WRN: forgetting %p chunk\n", p);
+ mcheck_registry[i] = 0;
+ }
+
+ mcheck_chunk_count = 0;
+}
+#endif
+#endif
diff --git a/common/spl/spl.c b/common/spl/spl.c
index b65c439e7aa..e06bc75d36b 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -909,6 +909,9 @@ ulong spl_relocate_stack_gd(void)
#if CONFIG_IS_ENABLED(DM)
dm_fixup_for_gd_move(new_gd);
#endif
+#if CONFIG_IS_ENABLED(LOG)
+ log_fixup_for_gd_move(new_gd);
+#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_RISCV)
gd = new_gd;
#endif
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 872df0c0fe8..e5195d460c4 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -550,7 +550,12 @@ static void *spl_get_fit_load_buffer(size_t size)
buf = malloc_cache_aligned(size);
if (!buf) {
pr_err("Could not get FIT buffer of %lu bytes\n", (ulong)size);
- pr_err("\tcheck CONFIG_SPL_SYS_MALLOC_SIZE\n");
+
+ if (IS_ENABLED(CONFIG_SPL_SYS_MALLOC))
+ pr_err("\tcheck CONFIG_SPL_SYS_MALLOC_SIZE\n");
+ else
+ pr_err("\tcheck CONFIG_SPL_SYS_MALLOC_F_LEN\n");
+
buf = spl_get_load_buffer(0, size);
}
return buf;
diff --git a/common/usb.c b/common/usb.c
index 836506dcd9e..99e6b857c74 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -28,6 +28,7 @@
#include <common.h>
#include <command.h>
#include <dm.h>
+#include <dm/device_compat.h>
#include <log.h>
#include <malloc.h>
#include <memalign.h>
@@ -1084,6 +1085,54 @@ static int usb_prepare_device(struct usb_device *dev, int addr, bool do_read,
return 0;
}
+static int usb_device_is_ignored(u16 id_vendor, u16 id_product)
+{
+ ulong vid, pid;
+ char *end;
+ const char *cur = NULL;
+
+ /* ignore list depends on env support */
+ if (!CONFIG_IS_ENABLED(ENV_SUPPORT))
+ return 0;
+
+ cur = env_get("usb_ignorelist");
+
+ /* parse "usb_ignorelist" strictly */
+ while (cur && cur[0] != '\0') {
+ vid = simple_strtoul(cur, &end, 0);
+ /*
+ * If strtoul did not parse a single digit or the next char is
+ * not ':' the ignore list is malformed.
+ */
+ if (cur == end || end[0] != ':')
+ return -EINVAL;
+
+ cur = end + 1;
+ pid = simple_strtoul(cur, &end, 0);
+ /* Consider '*' as wildcard for the product ID */
+ if (cur == end && end[0] == '*') {
+ pid = U16_MAX + 1;
+ end++;
+ }
+ /*
+ * The ignore list is malformed if no product ID / wildcard was
+ * parsed or entries are not separated by ',' or terminated with
+ * '\0'.
+ */
+ if (cur == end || (end[0] != ',' && end[0] != '\0'))
+ return -EINVAL;
+
+ if (id_vendor == vid && (pid > U16_MAX || id_product == pid))
+ return -ENODEV;
+
+ if (end[0] == '\0')
+ break;
+ cur = end + 1;
+ }
+
+ return 0;
+}
+
int usb_select_config(struct usb_device *dev)
{
unsigned char *tmpbuf = NULL;
@@ -1099,6 +1148,27 @@ int usb_select_config(struct usb_device *dev)
le16_to_cpus(&dev->descriptor.idProduct);
le16_to_cpus(&dev->descriptor.bcdDevice);
+ /* ignore devices from usb_ignorelist */
+ err = usb_device_is_ignored(dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ if (err == -ENODEV) {
+ debug("Ignoring USB device 0x%x:0x%x\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ return err;
+ } else if (err == -EINVAL) {
+ /*
+ * Continue on "usb_ignorelist" parsing errors. The list is
+ * parsed for each device returning the error would result in
+ * ignoring all USB devices.
+ * Since the parsing error is independent of the probed device
+ * report errors with printf instead of dev_err.
+ */
+ printf("usb_ignorelist parse error in \"%s\"\n",
+ env_get("usb_ignorelist"));
+ } else if (err < 0) {
+ return err;
+ }
+
/*
* Kingston DT Ultimate 32GB USB 3.0 seems to be extremely sensitive
* about this first Get Descriptor request. If there are any other
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 4cbc9acb738..820f591fc5b 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -24,6 +24,18 @@
#include <usb.h>
/*
+ * USB vendor and product IDs used for quirks.
+ */
+#define USB_VENDOR_ID_APPLE 0x05ac
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 0x029c
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 0x029a
+#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021 0x029f
+
+#define USB_VENDOR_ID_KEYCHRON 0x3434
+
+#define USB_HID_QUIRK_POLL_NO_REPORT_IDLE BIT(0)
+
+/*
* If overwrite_console returns 1, the stdin, stderr and stdout
* are switched to the serial port, else the settings in the
* environment are used
@@ -106,6 +118,8 @@ struct usb_kbd_pdata {
unsigned long last_report;
struct int_queue *intq;
+ uint32_t ifnum;
+
uint32_t repeat_delay;
uint32_t usb_in_pointer;
@@ -150,8 +164,8 @@ static void usb_kbd_put_queue(struct usb_kbd_pdata *data, u8 c)
*/
static void usb_kbd_setled(struct usb_device *dev)
{
- struct usb_interface *iface = &dev->config.if_desc[0];
struct usb_kbd_pdata *data = dev->privptr;
+ struct usb_interface *iface = &dev->config.if_desc[data->ifnum];
ALLOC_ALIGN_BUFFER(uint32_t, leds, 1, USB_DMA_MINALIGN);
*leds = data->flags & USB_KBD_LEDMASK;
@@ -365,7 +379,7 @@ static inline void usb_kbd_poll_for_event(struct usb_device *dev)
#if defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
struct usb_interface *iface;
struct usb_kbd_pdata *data = dev->privptr;
- iface = &dev->config.if_desc[0];
+ iface = &dev->config.if_desc[data->ifnum];
usb_get_report(dev, iface->desc.bInterfaceNumber,
1, 0, data->new, USB_KBD_BOOT_REPORT_SIZE);
if (memcmp(data->old, data->new, USB_KBD_BOOT_REPORT_SIZE)) {
@@ -464,6 +478,7 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
struct usb_interface *iface;
struct usb_endpoint_descriptor *ep;
struct usb_kbd_pdata *data;
+ unsigned int quirks = 0;
int epNum;
if (dev->descriptor.bNumConfigurations != 1)
@@ -496,6 +511,15 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
debug("USB KBD: found interrupt EP: 0x%x\n", ep->bEndpointAddress);
+ switch (dev->descriptor.idVendor) {
+ case USB_VENDOR_ID_APPLE:
+ case USB_VENDOR_ID_KEYCHRON:
+ quirks |= USB_HID_QUIRK_POLL_NO_REPORT_IDLE;
+ break;
+ default:
+ break;
+ }
+
data = malloc(sizeof(struct usb_kbd_pdata));
if (!data) {
printf("USB KBD: Error allocating private data\n");
@@ -509,6 +533,8 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
data->new = memalign(USB_DMA_MINALIGN,
roundup(USB_KBD_BOOT_REPORT_SIZE, USB_DMA_MINALIGN));
+ data->ifnum = ifnum;
+
/* Insert private data into USB device structure */
dev->privptr = data;
@@ -534,6 +560,14 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0);
#endif
+ /*
+ * Apple and Keychron keyboards do not report the device state. Reports
+ * are only returned during key presses.
+ */
+ if (quirks & USB_HID_QUIRK_POLL_NO_REPORT_IDLE) {
+ debug("USB KBD: quirk: skip testing device state\n");
+ return 1;
+ }
debug("USB KBD: enable interrupt pipe...\n");
#ifdef CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE
data->intq = create_int_queue(dev, data->intpipe, 1,
@@ -561,10 +595,17 @@ static int probe_usb_keyboard(struct usb_device *dev)
{
char *stdinname;
struct stdio_dev usb_kbd_dev;
+ unsigned int ifnum;
+ unsigned int max_ifnum = min((unsigned int)USB_MAX_ACTIVE_INTERFACES,
+ (unsigned int)dev->config.no_of_if);
int error;
/* Try probing the keyboard */
- if (usb_kbd_probe_dev(dev, 0) != 1)
+ for (ifnum = 0; ifnum < max_ifnum; ifnum++) {
+ if (usb_kbd_probe_dev(dev, ifnum) == 1)
+ break;
+ }
+ if (ifnum >= max_ifnum)
return -ENOENT;
/* Register the keyboard */
@@ -731,6 +772,18 @@ static const struct usb_device_id kbd_id_table[] = {
.bInterfaceSubClass = USB_SUB_HID_BOOT,
.bInterfaceProtocol = USB_PROT_HID_KEYBOARD,
},
+ {
+ USB_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
+ },
+ {
+ USB_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
+ },
+ {
+ USB_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
+ },
{ } /* Terminating entry */
};