mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-27 07:51:38 +00:00
Revert "Merge patch series "pxe: Precursor series for supporting read_all() in extlinux / PXE""
This reverts commit8bc3542384
, reversing changes made to698edd63ec
. There are still problems with this series to work out. Link: https://lore.kernel.org/u-boot/CAFLszTjw_MJbK9tpzVYi3XKGazcv55auBAdgVzcAVUta7dRqcg@mail.gmail.com/ Signed-off-by: Tom Rini <trini@konsulko.com>
This commit is contained in:
parent
2015662a67
commit
f892a7f397
17 changed files with 379 additions and 663 deletions
|
@ -28,13 +28,6 @@ struct Image_header {
|
||||||
uint32_t res5;
|
uint32_t res5;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool booti_is_valid(const void *img)
|
|
||||||
{
|
|
||||||
const struct Image_header *ih = img;
|
|
||||||
|
|
||||||
return ih->magic == le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
||||||
bool force_reloc)
|
bool force_reloc)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +39,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
||||||
|
|
||||||
ih = (struct Image_header *)map_sysmem(image, 0);
|
ih = (struct Image_header *)map_sysmem(image, 0);
|
||||||
|
|
||||||
if (!booti_is_valid(ih)) {
|
if (ih->magic != le32_to_cpu(LINUX_ARM64_IMAGE_MAGIC)) {
|
||||||
puts("Bad Linux ARM64 Image magic!\n");
|
puts("Bad Linux ARM64 Image magic!\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,6 @@ struct linux_image_h {
|
||||||
uint32_t res4; /* reserved */
|
uint32_t res4; /* reserved */
|
||||||
};
|
};
|
||||||
|
|
||||||
bool booti_is_valid(const void *img)
|
|
||||||
{
|
|
||||||
const struct linux_image_h *lhdr = img;
|
|
||||||
|
|
||||||
return lhdr->magic == LINUX_RISCV_IMAGE_MAGIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
||||||
bool force_reloc)
|
bool force_reloc)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +39,7 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
||||||
|
|
||||||
lhdr = (struct linux_image_h *)map_sysmem(image, 0);
|
lhdr = (struct linux_image_h *)map_sysmem(image, 0);
|
||||||
|
|
||||||
if (!booti_is_valid(lhdr)) {
|
if (lhdr->magic != LINUX_RISCV_IMAGE_MAGIC) {
|
||||||
puts("Bad Linux RISCV Image magic!\n");
|
puts("Bad Linux RISCV Image magic!\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,8 +89,3 @@ int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool booti_is_valid(const void *img)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
#include <asm/bootparam.h>
|
#include <asm/bootparam.h>
|
||||||
#include <asm/e820.h>
|
#include <asm/e820.h>
|
||||||
|
|
||||||
struct bootm_info;
|
|
||||||
|
|
||||||
/* linux i386 zImage/bzImage header. Offsets relative to
|
/* linux i386 zImage/bzImage header. Offsets relative to
|
||||||
* the start of the image */
|
* the start of the image */
|
||||||
|
|
||||||
|
@ -44,6 +42,43 @@ enum {
|
||||||
ZBOOT_STATE_COUNT = 5,
|
ZBOOT_STATE_COUNT = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct zboot_state - Current state of the boot
|
||||||
|
*
|
||||||
|
* @bzimage_addr: Address of the bzImage to boot, or 0 if the image has already
|
||||||
|
* been loaded and does not exist (as a cohesive whole) in memory
|
||||||
|
* @bzimage_size: Size of the bzImage, or 0 to detect this
|
||||||
|
* @initrd_addr: Address of the initial ramdisk, or 0 if none
|
||||||
|
* @initrd_size: Size of the initial ramdisk, or 0 if none
|
||||||
|
* @load_address: Address where the bzImage is moved before booting, either
|
||||||
|
* BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR
|
||||||
|
* This is set up when loading the zimage
|
||||||
|
* @base_ptr: Pointer to the boot parameters, typically at address
|
||||||
|
* DEFAULT_SETUP_BASE
|
||||||
|
* This is set up when loading the zimage
|
||||||
|
* @cmdline: Environment variable containing the 'override' command line, or
|
||||||
|
* NULL to use the one in the setup block
|
||||||
|
*/
|
||||||
|
struct zboot_state {
|
||||||
|
ulong bzimage_addr;
|
||||||
|
ulong bzimage_size;
|
||||||
|
ulong initrd_addr;
|
||||||
|
ulong initrd_size;
|
||||||
|
ulong load_address;
|
||||||
|
struct boot_params *base_ptr;
|
||||||
|
const char *cmdline;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct zboot_state state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zimage_dump() - Dump information about a zimage
|
||||||
|
*
|
||||||
|
* @base_ptr: Pointer to the boot parameters
|
||||||
|
* @show_cmdline: true to show the kernel command line
|
||||||
|
*/
|
||||||
|
void zimage_dump(struct boot_params *base_ptr, bool show_cmdline);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zboot_load() - Load a zimage
|
* zboot_load() - Load a zimage
|
||||||
*
|
*
|
||||||
|
@ -51,21 +86,21 @@ enum {
|
||||||
*
|
*
|
||||||
* Return: 0 if OK, -ve on error
|
* Return: 0 if OK, -ve on error
|
||||||
*/
|
*/
|
||||||
int zboot_load(struct bootm_info *bmi);
|
int zboot_load(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zboot_setup() - Set up the zboot image reeady for booting
|
* zboot_setup() - Set up the zboot image reeady for booting
|
||||||
*
|
*
|
||||||
* Return: 0 if OK, -ve on error
|
* Return: 0 if OK, -ve on error
|
||||||
*/
|
*/
|
||||||
int zboot_setup(struct bootm_info *bmi);
|
int zboot_setup(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zboot_go() - Start the image
|
* zboot_go() - Start the image
|
||||||
*
|
*
|
||||||
* Return: 0 if OK, -ve on error
|
* Return: 0 if OK, -ve on error
|
||||||
*/
|
*/
|
||||||
int zboot_go(struct bootm_info *bmi);
|
int zboot_go(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* load_zimage() - Load a zImage or bzImage
|
* load_zimage() - Load a zImage or bzImage
|
||||||
|
@ -104,7 +139,6 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
|
||||||
*
|
*
|
||||||
* Record information about a zimage so it can be booted
|
* Record information about a zimage so it can be booted
|
||||||
*
|
*
|
||||||
* @bmi: Bootm information
|
|
||||||
* @bzimage_addr: Address of the bzImage to boot
|
* @bzimage_addr: Address of the bzImage to boot
|
||||||
* @bzimage_size: Size of the bzImage, or 0 to detect this
|
* @bzimage_size: Size of the bzImage, or 0 to detect this
|
||||||
* @initrd_addr: Address of the initial ramdisk, or 0 if none
|
* @initrd_addr: Address of the initial ramdisk, or 0 if none
|
||||||
|
@ -115,17 +149,14 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
|
||||||
* @cmdline: Environment variable containing the 'override' command line, or
|
* @cmdline: Environment variable containing the 'override' command line, or
|
||||||
* NULL to use the one in the setup block
|
* NULL to use the one in the setup block
|
||||||
*/
|
*/
|
||||||
void zboot_start(struct bootm_info *bmi, ulong bzimage_addr, ulong bzimage_size,
|
void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr,
|
||||||
ulong initrd_addr, ulong initrd_size, ulong base_addr,
|
ulong initrd_size, ulong base_addr, const char *cmdline);
|
||||||
const char *cmdline);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zboot_info() - Show simple info about a zimage
|
* zboot_info() - Show simple info about a zimage
|
||||||
*
|
*
|
||||||
* Shows where the kernel was loaded and also the setup base
|
* Shows wherer the kernel was loaded and also the setup base
|
||||||
*
|
|
||||||
* @bmi: Bootm information
|
|
||||||
*/
|
*/
|
||||||
void zboot_info(struct bootm_info *bmi);
|
void zboot_info(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -55,6 +55,9 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
#define COMMAND_LINE_SIZE 2048
|
#define COMMAND_LINE_SIZE 2048
|
||||||
|
|
||||||
|
/* Current state of the boot */
|
||||||
|
struct zboot_state state;
|
||||||
|
|
||||||
static void build_command_line(char *command_line, int auto_boot)
|
static void build_command_line(char *command_line, int auto_boot)
|
||||||
{
|
{
|
||||||
char *env_command_line;
|
char *env_command_line;
|
||||||
|
@ -366,54 +369,54 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zboot_load(struct bootm_info *bmi)
|
int zboot_load(void)
|
||||||
{
|
{
|
||||||
struct boot_params *base_ptr;
|
struct boot_params *base_ptr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (bmi->base_ptr) {
|
if (state.base_ptr) {
|
||||||
struct boot_params *from = (struct boot_params *)bmi->base_ptr;
|
struct boot_params *from = (struct boot_params *)state.base_ptr;
|
||||||
|
|
||||||
base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE;
|
base_ptr = (struct boot_params *)DEFAULT_SETUP_BASE;
|
||||||
log_debug("Building boot_params at %lx\n", (ulong)base_ptr);
|
log_debug("Building boot_params at %lx\n", (ulong)base_ptr);
|
||||||
memset(base_ptr, '\0', sizeof(*base_ptr));
|
memset(base_ptr, '\0', sizeof(*base_ptr));
|
||||||
base_ptr->hdr = from->hdr;
|
base_ptr->hdr = from->hdr;
|
||||||
} else {
|
} else {
|
||||||
base_ptr = load_zimage((void *)bmi->bzimage_addr,
|
base_ptr = load_zimage((void *)state.bzimage_addr, state.bzimage_size,
|
||||||
bmi->bzimage_size, &bmi->load_address);
|
&state.load_address);
|
||||||
if (!base_ptr) {
|
if (!base_ptr) {
|
||||||
puts("## Kernel loading failed ...\n");
|
puts("## Kernel loading failed ...\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bmi->base_ptr = base_ptr;
|
state.base_ptr = base_ptr;
|
||||||
|
|
||||||
ret = env_set_hex("zbootbase", map_to_sysmem(bmi->base_ptr));
|
ret = env_set_hex("zbootbase", map_to_sysmem(state.base_ptr));
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = env_set_hex("zbootaddr", bmi->load_address);
|
ret = env_set_hex("zbootaddr", state.load_address);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zboot_setup(struct bootm_info *bmi)
|
int zboot_setup(void)
|
||||||
{
|
{
|
||||||
struct boot_params *base_ptr = bmi->base_ptr;
|
struct boot_params *base_ptr = state.base_ptr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
|
ret = setup_zimage(base_ptr, (char *)base_ptr + COMMAND_LINE_OFFSET,
|
||||||
0, bmi->initrd_addr, bmi->initrd_size,
|
0, state.initrd_addr, state.initrd_size,
|
||||||
(ulong)bmi->cmdline);
|
(ulong)state.cmdline);
|
||||||
if (ret)
|
if (ret)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zboot_go(struct bootm_info *bmi)
|
int zboot_go(void)
|
||||||
{
|
{
|
||||||
struct boot_params *params = bmi->base_ptr;
|
struct boot_params *params = state.base_ptr;
|
||||||
struct setup_header *hdr = ¶ms->hdr;
|
struct setup_header *hdr = ¶ms->hdr;
|
||||||
bool image_64bit;
|
bool image_64bit;
|
||||||
ulong entry;
|
ulong entry;
|
||||||
|
@ -421,7 +424,7 @@ int zboot_go(struct bootm_info *bmi)
|
||||||
|
|
||||||
disable_interrupts();
|
disable_interrupts();
|
||||||
|
|
||||||
entry = bmi->load_address;
|
entry = state.load_address;
|
||||||
image_64bit = false;
|
image_64bit = false;
|
||||||
if (IS_ENABLED(CONFIG_X86_64) &&
|
if (IS_ENABLED(CONFIG_X86_64) &&
|
||||||
(hdr->xloadflags & XLF_KERNEL_64)) {
|
(hdr->xloadflags & XLF_KERNEL_64)) {
|
||||||
|
@ -429,43 +432,30 @@ int zboot_go(struct bootm_info *bmi)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we assume that the kernel is in place */
|
/* we assume that the kernel is in place */
|
||||||
ret = boot_linux_kernel((ulong)bmi->base_ptr, entry, image_64bit);
|
ret = boot_linux_kernel((ulong)state.base_ptr, entry, image_64bit);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zboot_run(struct bootm_info *bmi)
|
int zboot_run(ulong addr, ulong size, ulong initrd, ulong initrd_size,
|
||||||
|
ulong base, char *cmdline)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = zboot_load(bmi);
|
zboot_start(addr, size, initrd, initrd_size, base, cmdline);
|
||||||
|
ret = zboot_load();
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("ld", ret);
|
return log_msg_ret("ld", ret);
|
||||||
ret = zboot_setup(bmi);
|
ret = zboot_setup();
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("set", ret);
|
return log_msg_ret("set", ret);
|
||||||
ret = zboot_go(bmi);
|
ret = zboot_go();
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("go", ret);
|
return log_msg_ret("go", ret);
|
||||||
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size,
|
|
||||||
ulong base, char *cmdline)
|
|
||||||
{
|
|
||||||
struct bootm_info bmi;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
bootm_init(&bmi);
|
|
||||||
zboot_start(&bmi, addr, size, initrd, initrd_size, base, cmdline);
|
|
||||||
ret = zboot_run(&bmi);
|
|
||||||
if (ret)
|
|
||||||
return log_msg_ret("zra", ret);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_num(const char *name, ulong value)
|
static void print_num(const char *name, ulong value)
|
||||||
{
|
{
|
||||||
printf("%-20s: %lx\n", name, value);
|
printf("%-20s: %lx\n", name, value);
|
||||||
|
@ -559,12 +549,11 @@ static void show_loader(struct setup_header *hdr)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void zimage_dump(struct bootm_info *bmi, bool show_cmdline)
|
void zimage_dump(struct boot_params *base_ptr, bool show_cmdline)
|
||||||
{
|
{
|
||||||
struct boot_params *base_ptr;
|
|
||||||
struct setup_header *hdr;
|
struct setup_header *hdr;
|
||||||
|
const char *version;
|
||||||
|
|
||||||
base_ptr = bmi->base_ptr;
|
|
||||||
printf("Setup located at %p:\n\n", base_ptr);
|
printf("Setup located at %p:\n\n", base_ptr);
|
||||||
print_num64("ACPI RSDP addr", base_ptr->acpi_rsdp_addr);
|
print_num64("ACPI RSDP addr", base_ptr->acpi_rsdp_addr);
|
||||||
|
|
||||||
|
@ -590,14 +579,10 @@ void zimage_dump(struct bootm_info *bmi, bool show_cmdline)
|
||||||
print_num("Real mode switch", hdr->realmode_swtch);
|
print_num("Real mode switch", hdr->realmode_swtch);
|
||||||
print_num("Start sys seg", hdr->start_sys_seg);
|
print_num("Start sys seg", hdr->start_sys_seg);
|
||||||
print_num("Kernel version", hdr->kernel_version);
|
print_num("Kernel version", hdr->kernel_version);
|
||||||
if (bmi->bzimage_addr) {
|
|
||||||
const char *version;
|
|
||||||
|
|
||||||
version = zimage_get_kernel_version(base_ptr,
|
version = zimage_get_kernel_version(base_ptr,
|
||||||
(void *)bmi->bzimage_addr);
|
(void *)state.bzimage_addr);
|
||||||
if (version)
|
if (version)
|
||||||
printf(" @%p: %s\n", version, version);
|
printf(" @%p: %s\n", version, version);
|
||||||
}
|
|
||||||
print_num("Type of loader", hdr->type_of_loader);
|
print_num("Type of loader", hdr->type_of_loader);
|
||||||
show_loader(hdr);
|
show_loader(hdr);
|
||||||
print_num("Load flags", hdr->loadflags);
|
print_num("Load flags", hdr->loadflags);
|
||||||
|
@ -638,24 +623,25 @@ void zimage_dump(struct bootm_info *bmi, bool show_cmdline)
|
||||||
print_num("Kernel info offset", hdr->kernel_info_offset);
|
print_num("Kernel info offset", hdr->kernel_info_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void zboot_start(struct bootm_info *bmi, ulong bzimage_addr, ulong bzimage_size,
|
void zboot_start(ulong bzimage_addr, ulong bzimage_size, ulong initrd_addr,
|
||||||
ulong initrd_addr, ulong initrd_size, ulong base_addr,
|
ulong initrd_size, ulong base_addr, const char *cmdline)
|
||||||
const char *cmdline)
|
|
||||||
{
|
{
|
||||||
bmi->bzimage_size = bzimage_size;
|
memset(&state, '\0', sizeof(state));
|
||||||
bmi->initrd_addr = initrd_addr;
|
|
||||||
bmi->initrd_size = initrd_size;
|
state.bzimage_size = bzimage_size;
|
||||||
|
state.initrd_addr = initrd_addr;
|
||||||
|
state.initrd_size = initrd_size;
|
||||||
if (base_addr) {
|
if (base_addr) {
|
||||||
bmi->base_ptr = map_sysmem(base_addr, 0);
|
state.base_ptr = map_sysmem(base_addr, 0);
|
||||||
bmi->load_address = bzimage_addr;
|
state.load_address = bzimage_addr;
|
||||||
} else {
|
} else {
|
||||||
bmi->bzimage_addr = bzimage_addr;
|
state.bzimage_addr = bzimage_addr;
|
||||||
}
|
}
|
||||||
bmi->cmdline = cmdline;
|
state.cmdline = cmdline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zboot_info(struct bootm_info *bmi)
|
void zboot_info(void)
|
||||||
{
|
{
|
||||||
printf("Kernel loaded at %08lx, setup_base=%p\n",
|
printf("Kernel loaded at %08lx, setup_base=%p\n",
|
||||||
bmi->load_address, bmi->base_ptr);
|
state.load_address, state.base_ptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o
|
||||||
obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o
|
obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o
|
||||||
obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o
|
obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o
|
||||||
|
|
||||||
obj-$(CONFIG_PXE_UTILS) += bootm.o pxe_utils.o
|
obj-$(CONFIG_PXE_UTILS) += pxe_utils.o
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
77
boot/bootm.c
77
boot/bootm.c
|
@ -146,7 +146,7 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images,
|
||||||
/* check image type, for FIT images get FIT kernel node */
|
/* check image type, for FIT images get FIT kernel node */
|
||||||
*os_data = *os_len = 0;
|
*os_data = *os_len = 0;
|
||||||
buf = map_sysmem(img_addr, 0);
|
buf = map_sysmem(img_addr, 0);
|
||||||
switch (genimg_get_format_comp(buf)) {
|
switch (genimg_get_format(buf)) {
|
||||||
#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
|
#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
|
||||||
case IMAGE_FORMAT_LEGACY:
|
case IMAGE_FORMAT_LEGACY:
|
||||||
printf("## Booting kernel from Legacy Image at %08lx ...\n",
|
printf("## Booting kernel from Legacy Image at %08lx ...\n",
|
||||||
|
@ -227,9 +227,6 @@ static int boot_get_kernel(const char *addr_fit, struct bootm_headers *images,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
case IMAGE_FORMAT_BOOTI:
|
|
||||||
*os_data = img_addr;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE);
|
bootstage_error(BOOTSTAGE_ID_CHECK_IMAGETYPE);
|
||||||
return -EPROTOTYPE;
|
return -EPROTOTYPE;
|
||||||
|
@ -289,35 +286,6 @@ static int bootm_pre_load(const char *addr_str)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int found_booti_os(enum image_comp_t comp)
|
|
||||||
{
|
|
||||||
images.os.load = images.os.image_start;
|
|
||||||
images.os.type = IH_TYPE_KERNEL;
|
|
||||||
images.os.os = IH_OS_LINUX;
|
|
||||||
images.os.comp = comp;
|
|
||||||
if (IS_ENABLED(CONFIG_RISCV_SMODE))
|
|
||||||
images.os.arch = IH_ARCH_RISCV;
|
|
||||||
else if (IS_ENABLED(CONFIG_ARM64))
|
|
||||||
images.os.arch = IH_ARCH_ARM64;
|
|
||||||
|
|
||||||
log_debug("load %lx start %lx len %lx ep %lx os %x comp %x\n",
|
|
||||||
images.os.load, images.os.image_start, images.os.image_len,
|
|
||||||
images.ep, images.os.os, images.os.comp);
|
|
||||||
if (comp != IH_COMP_NONE) {
|
|
||||||
images.os.load = env_get_hex("kernel_comp_addr_r", 0);
|
|
||||||
images.os.image_len = env_get_ulong("kernel_comp_size", 16, 0);
|
|
||||||
if (!images.os.load || !images.os.image_len) {
|
|
||||||
puts("kernel_comp_addr_r or kernel_comp_size is not provided!\n");
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
||||||
if (lmb_reserve(images.os.load, images.os.image_len, LMB_NONE)
|
|
||||||
< 0)
|
|
||||||
return -EXDEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bootm_find_os(): Find the OS to boot
|
* bootm_find_os(): Find the OS to boot
|
||||||
*
|
*
|
||||||
|
@ -422,28 +390,7 @@ static int bootm_find_os(const char *cmd_name, const char *addr_fit)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case IMAGE_FORMAT_BOOTI:
|
|
||||||
if (IS_ENABLED(CONFIG_CMD_BOOTI)) {
|
|
||||||
if (found_booti_os(IH_COMP_NONE))
|
|
||||||
return 1;
|
|
||||||
ep_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fallthrough;
|
|
||||||
default:
|
default:
|
||||||
/* any compressed image is probably a booti image */
|
|
||||||
if (IS_ENABLED(CONFIG_CMD_BOOTI)) {
|
|
||||||
int comp;
|
|
||||||
|
|
||||||
comp = image_decomp_type(os_hdr, 2);
|
|
||||||
if (comp != IH_COMP_NONE) {
|
|
||||||
if (found_booti_os(comp))
|
|
||||||
return 1;
|
|
||||||
ep_found = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
puts("ERROR: unknown image format type!\n");
|
puts("ERROR: unknown image format type!\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -594,7 +541,6 @@ int bootm_find_images(ulong img_addr, const char *conf_ramdisk,
|
||||||
static int bootm_find_other(ulong img_addr, const char *conf_ramdisk,
|
static int bootm_find_other(ulong img_addr, const char *conf_ramdisk,
|
||||||
const char *conf_fdt)
|
const char *conf_fdt)
|
||||||
{
|
{
|
||||||
log_debug("find_other type %x os %x\n", images.os.type, images.os.os);
|
|
||||||
if ((images.os.type == IH_TYPE_KERNEL ||
|
if ((images.os.type == IH_TYPE_KERNEL ||
|
||||||
images.os.type == IH_TYPE_KERNEL_NOLOAD ||
|
images.os.type == IH_TYPE_KERNEL_NOLOAD ||
|
||||||
images.os.type == IH_TYPE_MULTI) &&
|
images.os.type == IH_TYPE_MULTI) &&
|
||||||
|
@ -683,17 +629,15 @@ static int bootm_load_os(struct bootm_headers *images, int boot_progress)
|
||||||
debug("Allocated %lx bytes at %lx for kernel (size %lx) decompression\n",
|
debug("Allocated %lx bytes at %lx for kernel (size %lx) decompression\n",
|
||||||
req_size, load, image_len);
|
req_size, load, image_len);
|
||||||
}
|
}
|
||||||
log_debug("load_os load %lx image_start %lx image_len %lx\n", load,
|
|
||||||
image_start, image_len);
|
|
||||||
|
|
||||||
load_buf = map_sysmem(load, 0);
|
load_buf = map_sysmem(load, 0);
|
||||||
image_buf = map_sysmem(os.image_start, image_len);
|
image_buf = map_sysmem(os.image_start, image_len);
|
||||||
err = image_decomp(os.comp, load, os.image_start, os.type,
|
err = image_decomp(os.comp, load, os.image_start, os.type,
|
||||||
load_buf, image_buf, image_len, bootm_len(),
|
load_buf, image_buf, image_len,
|
||||||
&load_end);
|
CONFIG_SYS_BOOTM_LEN, &load_end);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = handle_decomp_error(os.comp, load_end - load, bootm_len(),
|
err = handle_decomp_error(os.comp, load_end - load,
|
||||||
err);
|
CONFIG_SYS_BOOTM_LEN, err);
|
||||||
bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
|
bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1166,10 +1110,6 @@ int boot_run(struct bootm_info *bmi, const char *cmd, int extra_states)
|
||||||
states |= BOOTM_STATE_RAMDISK;
|
states |= BOOTM_STATE_RAMDISK;
|
||||||
states |= extra_states;
|
states |= extra_states;
|
||||||
|
|
||||||
log_debug("cmd '%s' states %x addr_img '%s' conf_ramdisk '%s' conf_fdt '%s' images %p\n",
|
|
||||||
cmd, states, bmi->addr_img, bmi->conf_ramdisk, bmi->conf_fdt,
|
|
||||||
bmi->images);
|
|
||||||
|
|
||||||
return bootm_run_states(bmi, states);
|
return bootm_run_states(bmi, states);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1187,9 +1127,7 @@ int bootz_run(struct bootm_info *bmi)
|
||||||
|
|
||||||
int booti_run(struct bootm_info *bmi)
|
int booti_run(struct bootm_info *bmi)
|
||||||
{
|
{
|
||||||
return boot_run(bmi, "booti", BOOTM_STATE_START | BOOTM_STATE_FINDOS |
|
return boot_run(bmi, "booti", 0);
|
||||||
BOOTM_STATE_PRE_LOAD | BOOTM_STATE_FINDOTHER |
|
|
||||||
BOOTM_STATE_LOADOS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bootm_boot_start(ulong addr, const char *cmdline)
|
int bootm_boot_start(ulong addr, const char *cmdline)
|
||||||
|
@ -1228,8 +1166,7 @@ void bootm_init(struct bootm_info *bmi)
|
||||||
{
|
{
|
||||||
memset(bmi, '\0', sizeof(struct bootm_info));
|
memset(bmi, '\0', sizeof(struct bootm_info));
|
||||||
bmi->boot_progress = true;
|
bmi->boot_progress = true;
|
||||||
if (IS_ENABLED(CONFIG_CMD_BOOTM) || IS_ENABLED(CONFIG_CMD_BOOTZ) ||
|
if (IS_ENABLED(CONFIG_CMD_BOOTM))
|
||||||
IS_ENABLED(CONFIG_CMD_BOOTI) || IS_ENABLED(CONFIG_PXE_UTILS))
|
|
||||||
bmi->images = &images;
|
bmi->images = &images;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -446,8 +446,8 @@ static int cros_boot(struct udevice *dev, struct bootflow *bflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_X86)) {
|
if (IS_ENABLED(CONFIG_X86)) {
|
||||||
ret = zboot_run_args(map_to_sysmem(bflow->buf), bflow->size, 0,
|
ret = zboot_run(map_to_sysmem(bflow->buf), bflow->size, 0, 0,
|
||||||
0, map_to_sysmem(bflow->x86_setup),
|
map_to_sysmem(bflow->x86_setup),
|
||||||
bflow->cmdline);
|
bflow->cmdline);
|
||||||
} else {
|
} else {
|
||||||
ret = bootm_boot_start(map_to_sysmem(bflow->buf),
|
ret = bootm_boot_start(map_to_sysmem(bflow->buf),
|
||||||
|
|
|
@ -234,7 +234,21 @@ ulong genimg_get_kernel_addr(char * const img_addr)
|
||||||
&fit_uname_kernel);
|
&fit_uname_kernel);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum image_fmt_t genimg_get_format(const void *img_addr)
|
/**
|
||||||
|
* genimg_get_format - get image format type
|
||||||
|
* @img_addr: image start address
|
||||||
|
*
|
||||||
|
* genimg_get_format() checks whether provided address points to a valid
|
||||||
|
* legacy or FIT image.
|
||||||
|
*
|
||||||
|
* New uImage format and FDT blob are based on a libfdt. FDT blob
|
||||||
|
* may be passed directly or embedded in a FIT image. In both situations
|
||||||
|
* genimg_get_format() must be able to dectect libfdt header.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* image format type or IMAGE_FORMAT_INVALID if no image is present
|
||||||
|
*/
|
||||||
|
int genimg_get_format(const void *img_addr)
|
||||||
{
|
{
|
||||||
if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) {
|
if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) {
|
||||||
const struct legacy_img_hdr *hdr;
|
const struct legacy_img_hdr *hdr;
|
||||||
|
@ -250,24 +264,10 @@ enum image_fmt_t genimg_get_format(const void *img_addr)
|
||||||
if (IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE) &&
|
if (IS_ENABLED(CONFIG_ANDROID_BOOT_IMAGE) &&
|
||||||
is_android_boot_image_header(img_addr))
|
is_android_boot_image_header(img_addr))
|
||||||
return IMAGE_FORMAT_ANDROID;
|
return IMAGE_FORMAT_ANDROID;
|
||||||
if (IS_ENABLED(CONFIG_CMD_BOOTI) &&
|
|
||||||
booti_is_valid(img_addr))
|
|
||||||
return IMAGE_FORMAT_BOOTI;
|
|
||||||
|
|
||||||
return IMAGE_FORMAT_INVALID;
|
return IMAGE_FORMAT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum image_fmt_t genimg_get_format_comp(const void *img_addr)
|
|
||||||
{
|
|
||||||
enum image_fmt_t fmt = genimg_get_format(img_addr);
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_CMD_BOOTI) && fmt == IMAGE_FORMAT_INVALID &&
|
|
||||||
image_decomp_type(img_addr, 2) != IH_COMP_NONE)
|
|
||||||
fmt = IMAGE_FORMAT_BOOTI;
|
|
||||||
|
|
||||||
return fmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fit_has_config - check if there is a valid FIT configuration
|
* fit_has_config - check if there is a valid FIT configuration
|
||||||
* @images: pointer to the bootm command headers structure
|
* @images: pointer to the bootm command headers structure
|
||||||
|
@ -364,7 +364,7 @@ static int select_ramdisk(struct bootm_headers *images, const char *select, u8 a
|
||||||
* check image type, for FIT images get FIT node.
|
* check image type, for FIT images get FIT node.
|
||||||
*/
|
*/
|
||||||
buf = map_sysmem(rd_addr, 0);
|
buf = map_sysmem(rd_addr, 0);
|
||||||
switch (genimg_get_format_comp(buf)) {
|
switch (genimg_get_format(buf)) {
|
||||||
case IMAGE_FORMAT_LEGACY:
|
case IMAGE_FORMAT_LEGACY:
|
||||||
if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) {
|
if (CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)) {
|
||||||
const struct legacy_img_hdr *rd_hdr;
|
const struct legacy_img_hdr *rd_hdr;
|
||||||
|
@ -434,10 +434,6 @@ static int select_ramdisk(struct bootm_headers *images, const char *select, u8 a
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IMAGE_FORMAT_BOOTI:
|
|
||||||
break;
|
|
||||||
case IMAGE_FORMAT_INVALID:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!done) {
|
if (!done) {
|
||||||
|
|
419
boot/pxe_utils.c
419
boot/pxe_utils.c
|
@ -7,7 +7,6 @@
|
||||||
#define LOG_CATEGORY LOGC_BOOT
|
#define LOG_CATEGORY LOGC_BOOT
|
||||||
|
|
||||||
#include <bootflow.h>
|
#include <bootflow.h>
|
||||||
#include <bootm.h>
|
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <env.h>
|
#include <env.h>
|
||||||
|
@ -433,223 +432,6 @@ skip_overlay:
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* label_process_fdt() - Process FDT for the label
|
|
||||||
*
|
|
||||||
* @ctx: PXE context
|
|
||||||
* @label: Label to process
|
|
||||||
* @kernel_addr: String containing kernel address
|
|
||||||
* @fdt_argp: bootm argument to fill in, for FDT
|
|
||||||
* Return: 0 if OK, -ENOMEM if out of memory, -ENOENT if FDT file could not be
|
|
||||||
* loaded
|
|
||||||
*
|
|
||||||
* fdt usage is optional:
|
|
||||||
* It handles the following scenarios.
|
|
||||||
*
|
|
||||||
* Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
|
|
||||||
* defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
|
|
||||||
* bootm, and adjust argc appropriately.
|
|
||||||
*
|
|
||||||
* If retrieve fails and no exact fdt blob is specified in pxe file with
|
|
||||||
* "fdt" label, try Scenario 2.
|
|
||||||
*
|
|
||||||
* Scenario 2: If there is an fdt_addr specified, pass it along to
|
|
||||||
* bootm, and adjust argc appropriately.
|
|
||||||
*
|
|
||||||
* Scenario 3: If there is an fdtcontroladdr specified, pass it along to
|
|
||||||
* bootm, and adjust argc appropriately, unless the image type is fitImage.
|
|
||||||
*
|
|
||||||
* Scenario 4: fdt blob is not available.
|
|
||||||
*/
|
|
||||||
static int label_process_fdt(struct pxe_context *ctx, struct pxe_label *label,
|
|
||||||
char *kernel_addr, const char **fdt_argp)
|
|
||||||
{
|
|
||||||
/* For FIT, the label can be identical to kernel one */
|
|
||||||
if (label->fdt && !strcmp(label->kernel_label, label->fdt)) {
|
|
||||||
*fdt_argp = kernel_addr;
|
|
||||||
/* if fdt label is defined then get fdt from server */
|
|
||||||
} else if (*fdt_argp) {
|
|
||||||
char *fdtfile = NULL;
|
|
||||||
char *fdtfilefree = NULL;
|
|
||||||
|
|
||||||
if (label->fdt) {
|
|
||||||
if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
|
|
||||||
if (strcmp("-", label->fdt))
|
|
||||||
fdtfile = label->fdt;
|
|
||||||
} else {
|
|
||||||
fdtfile = label->fdt;
|
|
||||||
}
|
|
||||||
} else if (label->fdtdir) {
|
|
||||||
char *f1, *f2, *f3, *f4, *slash;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
f1 = env_get("fdtfile");
|
|
||||||
if (f1) {
|
|
||||||
f2 = "";
|
|
||||||
f3 = "";
|
|
||||||
f4 = "";
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* For complex cases where this code doesn't
|
|
||||||
* generate the correct filename, the board
|
|
||||||
* code should set $fdtfile during early boot,
|
|
||||||
* or the boot scripts should set $fdtfile
|
|
||||||
* before invoking "pxe" or "sysboot".
|
|
||||||
*/
|
|
||||||
f1 = env_get("soc");
|
|
||||||
f2 = "-";
|
|
||||||
f3 = env_get("board");
|
|
||||||
f4 = ".dtb";
|
|
||||||
if (!f1) {
|
|
||||||
f1 = "";
|
|
||||||
f2 = "";
|
|
||||||
}
|
|
||||||
if (!f3) {
|
|
||||||
f2 = "";
|
|
||||||
f3 = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = strlen(label->fdtdir);
|
|
||||||
if (!len)
|
|
||||||
slash = "./";
|
|
||||||
else if (label->fdtdir[len - 1] != '/')
|
|
||||||
slash = "/";
|
|
||||||
else
|
|
||||||
slash = "";
|
|
||||||
|
|
||||||
len = strlen(label->fdtdir) + strlen(slash) +
|
|
||||||
strlen(f1) + strlen(f2) + strlen(f3) +
|
|
||||||
strlen(f4) + 1;
|
|
||||||
fdtfilefree = malloc(len);
|
|
||||||
if (!fdtfilefree) {
|
|
||||||
printf("malloc fail (FDT filename)\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
|
|
||||||
label->fdtdir, slash, f1, f2, f3, f4);
|
|
||||||
fdtfile = fdtfilefree;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fdtfile) {
|
|
||||||
int err = get_relfile_envaddr(ctx, fdtfile,
|
|
||||||
"fdt_addr_r",
|
|
||||||
(enum bootflow_img_t)IH_TYPE_FLATDT, NULL);
|
|
||||||
|
|
||||||
free(fdtfilefree);
|
|
||||||
if (err < 0) {
|
|
||||||
*fdt_argp = NULL;
|
|
||||||
|
|
||||||
if (label->fdt) {
|
|
||||||
printf("Skipping %s for failure retrieving FDT\n",
|
|
||||||
label->name);
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (label->fdtdir) {
|
|
||||||
printf("Skipping fdtdir %s for failure retrieving dts\n",
|
|
||||||
label->fdtdir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (label->kaslrseed)
|
|
||||||
label_boot_kaslrseed();
|
|
||||||
|
|
||||||
#ifdef CONFIG_OF_LIBFDT_OVERLAY
|
|
||||||
if (label->fdtoverlays)
|
|
||||||
label_boot_fdtoverlay(ctx, label);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
*fdt_argp = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* label_run_boot() - Set up the FDT and call the appropriate bootm/z/i command
|
|
||||||
*
|
|
||||||
* @ctx: PXE context
|
|
||||||
* @label: Label to process
|
|
||||||
* @kernel_addr: String containing kernel address (cannot be NULL)
|
|
||||||
* @initrd_addr_str: String containing initrd address (NULL if none)
|
|
||||||
* @initrd_filesize: String containing initrd size (only used if
|
|
||||||
* @initrd_addr_str)
|
|
||||||
* @initrd_str: initrd string to process (only used if @initrd_addr_str)
|
|
||||||
* Return: does not return on success, or returns 0 if the boot command
|
|
||||||
* returned, or -ve error value on error
|
|
||||||
*/
|
|
||||||
static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label,
|
|
||||||
char *kernel_addr, char *initrd_addr_str,
|
|
||||||
char *initrd_filesize, char *initrd_str)
|
|
||||||
{
|
|
||||||
struct bootm_info bmi;
|
|
||||||
ulong kernel_addr_r;
|
|
||||||
void *buf;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
bootm_init(&bmi);
|
|
||||||
|
|
||||||
bmi.conf_fdt = env_get("fdt_addr_r");
|
|
||||||
|
|
||||||
ret = label_process_fdt(ctx, label, kernel_addr, &bmi.conf_fdt);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
bmi.addr_img = kernel_addr;
|
|
||||||
bootm_x86_set(&bmi, bzimage_addr, hextoul(kernel_addr, NULL));
|
|
||||||
|
|
||||||
if (initrd_addr_str) {
|
|
||||||
bmi.conf_ramdisk = initrd_str;
|
|
||||||
bootm_x86_set(&bmi, initrd_addr,
|
|
||||||
hextoul(initrd_addr_str, NULL));
|
|
||||||
bootm_x86_set(&bmi, initrd_size,
|
|
||||||
hextoul(initrd_filesize, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bmi.conf_fdt) {
|
|
||||||
if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) ||
|
|
||||||
strcmp("-", label->fdt))
|
|
||||||
bmi.conf_fdt = env_get("fdt_addr");
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel_addr_r = genimg_get_kernel_addr(kernel_addr);
|
|
||||||
buf = map_sysmem(kernel_addr_r, 0);
|
|
||||||
|
|
||||||
if (!bmi.conf_fdt && genimg_get_format(buf) != IMAGE_FORMAT_FIT) {
|
|
||||||
if (!IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS) ||
|
|
||||||
strcmp("-", label->fdt))
|
|
||||||
bmi.conf_fdt = env_get("fdtcontroladdr");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try bootm for legacy and FIT format image */
|
|
||||||
if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID &&
|
|
||||||
IS_ENABLED(CONFIG_CMD_BOOTM)) {
|
|
||||||
log_debug("using bootm\n");
|
|
||||||
ret = bootm_run(&bmi);
|
|
||||||
/* Try booting an AArch64 Linux kernel image */
|
|
||||||
} else if (IS_ENABLED(CONFIG_CMD_BOOTI)) {
|
|
||||||
log_debug("using booti\n");
|
|
||||||
ret = booti_run(&bmi);
|
|
||||||
/* Try booting a Image */
|
|
||||||
} else if (IS_ENABLED(CONFIG_CMD_BOOTZ)) {
|
|
||||||
log_debug("using bootz\n");
|
|
||||||
ret = bootz_run(&bmi);
|
|
||||||
/* Try booting an x86_64 Linux kernel image */
|
|
||||||
} else if (IS_ENABLED(CONFIG_CMD_ZBOOT)) {
|
|
||||||
log_debug("using zboot\n");
|
|
||||||
ret = zboot_run(&bmi);
|
|
||||||
}
|
|
||||||
|
|
||||||
unmap_sysmem(buf);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* label_boot() - Boot according to the contents of a pxe_label
|
* label_boot() - Boot according to the contents of a pxe_label
|
||||||
*
|
*
|
||||||
|
@ -672,6 +454,8 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label,
|
||||||
*/
|
*/
|
||||||
static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
|
static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
|
||||||
{
|
{
|
||||||
|
char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
|
||||||
|
char *zboot_argv[] = { "zboot", NULL, "0", NULL, NULL };
|
||||||
char *kernel_addr = NULL;
|
char *kernel_addr = NULL;
|
||||||
char *initrd_addr_str = NULL;
|
char *initrd_addr_str = NULL;
|
||||||
char initrd_filesize[10];
|
char initrd_filesize[10];
|
||||||
|
@ -679,6 +463,11 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
|
||||||
char mac_str[29] = "";
|
char mac_str[29] = "";
|
||||||
char ip_str[68] = "";
|
char ip_str[68] = "";
|
||||||
char *fit_addr = NULL;
|
char *fit_addr = NULL;
|
||||||
|
int bootm_argc = 2;
|
||||||
|
int zboot_argc = 3;
|
||||||
|
int len = 0;
|
||||||
|
ulong kernel_addr_r;
|
||||||
|
void *buf;
|
||||||
|
|
||||||
label_print(label);
|
label_print(label);
|
||||||
|
|
||||||
|
@ -723,12 +512,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
|
||||||
initrd_addr_str = kernel_addr;
|
initrd_addr_str = kernel_addr;
|
||||||
} else if (label->initrd) {
|
} else if (label->initrd) {
|
||||||
ulong size;
|
ulong size;
|
||||||
int ret;
|
if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r",
|
||||||
|
|
||||||
ret = get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r",
|
|
||||||
(enum bootflow_img_t)IH_TYPE_RAMDISK,
|
(enum bootflow_img_t)IH_TYPE_RAMDISK,
|
||||||
&size);
|
&size) < 0) {
|
||||||
if (ret < 0) {
|
|
||||||
printf("Skipping %s for failure retrieving initrd\n",
|
printf("Skipping %s for failure retrieving initrd\n",
|
||||||
label->name);
|
label->name);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -772,7 +558,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (label->append)
|
if (label->append)
|
||||||
strlcpy(bootargs, label->append, sizeof(bootargs));
|
strncpy(bootargs, label->append, sizeof(bootargs));
|
||||||
|
|
||||||
strcat(bootargs, ip_str);
|
strcat(bootargs, ip_str);
|
||||||
strcat(bootargs, mac_str);
|
strcat(bootargs, mac_str);
|
||||||
|
@ -783,14 +569,191 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
|
||||||
printf("append: %s\n", finalbootargs);
|
printf("append: %s\n", finalbootargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
label_run_boot(ctx, label, kernel_addr, initrd_addr_str,
|
/*
|
||||||
initrd_filesize, initrd_str);
|
* fdt usage is optional:
|
||||||
/* ignore the error value since we are going to fail anyway */
|
* It handles the following scenarios.
|
||||||
|
*
|
||||||
|
* Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is
|
||||||
|
* defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to
|
||||||
|
* bootm, and adjust argc appropriately.
|
||||||
|
*
|
||||||
|
* If retrieve fails and no exact fdt blob is specified in pxe file with
|
||||||
|
* "fdt" label, try Scenario 2.
|
||||||
|
*
|
||||||
|
* Scenario 2: If there is an fdt_addr specified, pass it along to
|
||||||
|
* bootm, and adjust argc appropriately.
|
||||||
|
*
|
||||||
|
* Scenario 3: If there is an fdtcontroladdr specified, pass it along to
|
||||||
|
* bootm, and adjust argc appropriately, unless the image type is fitImage.
|
||||||
|
*
|
||||||
|
* Scenario 4: fdt blob is not available.
|
||||||
|
*/
|
||||||
|
bootm_argv[3] = env_get("fdt_addr_r");
|
||||||
|
|
||||||
|
/* For FIT, the label can be identical to kernel one */
|
||||||
|
if (label->fdt && !strcmp(label->kernel_label, label->fdt)) {
|
||||||
|
bootm_argv[3] = kernel_addr;
|
||||||
|
/* if fdt label is defined then get fdt from server */
|
||||||
|
} else if (bootm_argv[3]) {
|
||||||
|
char *fdtfile = NULL;
|
||||||
|
char *fdtfilefree = NULL;
|
||||||
|
|
||||||
|
if (label->fdt) {
|
||||||
|
if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
|
||||||
|
if (strcmp("-", label->fdt))
|
||||||
|
fdtfile = label->fdt;
|
||||||
|
} else {
|
||||||
|
fdtfile = label->fdt;
|
||||||
|
}
|
||||||
|
} else if (label->fdtdir) {
|
||||||
|
char *f1, *f2, *f3, *f4, *slash;
|
||||||
|
|
||||||
|
f1 = env_get("fdtfile");
|
||||||
|
if (f1) {
|
||||||
|
f2 = "";
|
||||||
|
f3 = "";
|
||||||
|
f4 = "";
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* For complex cases where this code doesn't
|
||||||
|
* generate the correct filename, the board
|
||||||
|
* code should set $fdtfile during early boot,
|
||||||
|
* or the boot scripts should set $fdtfile
|
||||||
|
* before invoking "pxe" or "sysboot".
|
||||||
|
*/
|
||||||
|
f1 = env_get("soc");
|
||||||
|
f2 = "-";
|
||||||
|
f3 = env_get("board");
|
||||||
|
f4 = ".dtb";
|
||||||
|
if (!f1) {
|
||||||
|
f1 = "";
|
||||||
|
f2 = "";
|
||||||
|
}
|
||||||
|
if (!f3) {
|
||||||
|
f2 = "";
|
||||||
|
f3 = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(label->fdtdir);
|
||||||
|
if (!len)
|
||||||
|
slash = "./";
|
||||||
|
else if (label->fdtdir[len - 1] != '/')
|
||||||
|
slash = "/";
|
||||||
|
else
|
||||||
|
slash = "";
|
||||||
|
|
||||||
|
len = strlen(label->fdtdir) + strlen(slash) +
|
||||||
|
strlen(f1) + strlen(f2) + strlen(f3) +
|
||||||
|
strlen(f4) + 1;
|
||||||
|
fdtfilefree = malloc(len);
|
||||||
|
if (!fdtfilefree) {
|
||||||
|
printf("malloc fail (FDT filename)\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(fdtfilefree, len, "%s%s%s%s%s%s",
|
||||||
|
label->fdtdir, slash, f1, f2, f3, f4);
|
||||||
|
fdtfile = fdtfilefree;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fdtfile) {
|
||||||
|
int err = get_relfile_envaddr(ctx, fdtfile,
|
||||||
|
"fdt_addr_r",
|
||||||
|
(enum bootflow_img_t)IH_TYPE_FLATDT, NULL);
|
||||||
|
|
||||||
|
free(fdtfilefree);
|
||||||
|
if (err < 0) {
|
||||||
|
bootm_argv[3] = NULL;
|
||||||
|
|
||||||
|
if (label->fdt) {
|
||||||
|
printf("Skipping %s for failure retrieving FDT\n",
|
||||||
|
label->name);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (label->fdtdir) {
|
||||||
|
printf("Skipping fdtdir %s for failure retrieving dts\n",
|
||||||
|
label->fdtdir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (label->kaslrseed)
|
||||||
|
label_boot_kaslrseed();
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF_LIBFDT_OVERLAY
|
||||||
|
if (label->fdtoverlays)
|
||||||
|
label_boot_fdtoverlay(ctx, label);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
bootm_argv[3] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bootm_argv[1] = kernel_addr;
|
||||||
|
zboot_argv[1] = kernel_addr;
|
||||||
|
|
||||||
|
if (initrd_addr_str) {
|
||||||
|
bootm_argv[2] = initrd_str;
|
||||||
|
bootm_argc = 3;
|
||||||
|
|
||||||
|
zboot_argv[3] = initrd_addr_str;
|
||||||
|
zboot_argv[4] = initrd_filesize;
|
||||||
|
zboot_argc = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bootm_argv[3]) {
|
||||||
|
if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
|
||||||
|
if (strcmp("-", label->fdt))
|
||||||
|
bootm_argv[3] = env_get("fdt_addr");
|
||||||
|
} else {
|
||||||
|
bootm_argv[3] = env_get("fdt_addr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel_addr_r = genimg_get_kernel_addr(kernel_addr);
|
||||||
|
buf = map_sysmem(kernel_addr_r, 0);
|
||||||
|
|
||||||
|
if (!bootm_argv[3] && genimg_get_format(buf) != IMAGE_FORMAT_FIT) {
|
||||||
|
if (IS_ENABLED(CONFIG_SUPPORT_PASSING_ATAGS)) {
|
||||||
|
if (strcmp("-", label->fdt))
|
||||||
|
bootm_argv[3] = env_get("fdtcontroladdr");
|
||||||
|
} else {
|
||||||
|
bootm_argv[3] = env_get("fdtcontroladdr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootm_argv[3]) {
|
||||||
|
if (!bootm_argv[2])
|
||||||
|
bootm_argv[2] = "-";
|
||||||
|
bootm_argc = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try bootm for legacy and FIT format image */
|
||||||
|
if (genimg_get_format(buf) != IMAGE_FORMAT_INVALID &&
|
||||||
|
IS_ENABLED(CONFIG_CMD_BOOTM)) {
|
||||||
|
log_debug("using bootm\n");
|
||||||
|
do_bootm(ctx->cmdtp, 0, bootm_argc, bootm_argv);
|
||||||
|
/* Try booting an AArch64 Linux kernel image */
|
||||||
|
} else if (IS_ENABLED(CONFIG_CMD_BOOTI)) {
|
||||||
|
log_debug("using booti\n");
|
||||||
|
do_booti(ctx->cmdtp, 0, bootm_argc, bootm_argv);
|
||||||
|
/* Try booting a Image */
|
||||||
|
} else if (IS_ENABLED(CONFIG_CMD_BOOTZ)) {
|
||||||
|
log_debug("using bootz\n");
|
||||||
|
do_bootz(ctx->cmdtp, 0, bootm_argc, bootm_argv);
|
||||||
|
/* Try booting an x86_64 Linux kernel image */
|
||||||
|
} else if (IS_ENABLED(CONFIG_CMD_ZBOOT)) {
|
||||||
|
log_debug("using zboot\n");
|
||||||
|
do_zboot_parent(ctx->cmdtp, 0, zboot_argc, zboot_argv, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap_sysmem(buf);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
free(fit_addr);
|
free(fit_addr);
|
||||||
|
|
||||||
return 1; /* returning is always failure */
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** enum token_type - Tokens for the pxe file parser */
|
/** enum token_type - Tokens for the pxe file parser */
|
||||||
|
|
|
@ -380,13 +380,7 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
bflow = std->cur_bootflow;
|
bflow = std->cur_bootflow;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_X86) && x86_setup) {
|
if (IS_ENABLED(CONFIG_X86) && x86_setup) {
|
||||||
struct bootm_info bmi;
|
zimage_dump(bflow->x86_setup, false);
|
||||||
|
|
||||||
bootm_init(&bmi);
|
|
||||||
/* we don't know this at present */
|
|
||||||
bootm_x86_set(&bmi, bzimage_addr, 0);
|
|
||||||
bootm_x86_set(&bmi, base_ptr, bflow->x86_setup);
|
|
||||||
zimage_dump(&bmi, false);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
88
cmd/net.c
88
cmd/net.c
|
@ -297,15 +297,13 @@ static void netboot_update_env(void)
|
||||||
/**
|
/**
|
||||||
* parse_addr_size() - parse address and size arguments for tftpput
|
* parse_addr_size() - parse address and size arguments for tftpput
|
||||||
*
|
*
|
||||||
* @argv: command line arguments (argv[1] and argv[2] must be valid)
|
* @argv: command line arguments
|
||||||
* @addrp: returns the address, on success
|
|
||||||
* @sizep: returns the size, on success
|
|
||||||
* Return: 0 on success
|
* Return: 0 on success
|
||||||
*/
|
*/
|
||||||
static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep)
|
static int parse_addr_size(char * const argv[])
|
||||||
{
|
{
|
||||||
if (strict_strtoul(argv[1], 16, addrp) < 0 ||
|
if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 ||
|
||||||
strict_strtoul(argv[2], 16, sizep) < 0) {
|
strict_strtoul(argv[2], 16, &image_save_size) < 0) {
|
||||||
printf("Invalid address/size\n");
|
printf("Invalid address/size\n");
|
||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
}
|
}
|
||||||
|
@ -315,31 +313,24 @@ static int parse_addr_size(char * const argv[], ulong *addrp, ulong *sizep)
|
||||||
/**
|
/**
|
||||||
* parse_args() - parse command line arguments
|
* parse_args() - parse command line arguments
|
||||||
*
|
*
|
||||||
* Sets:
|
|
||||||
* - image_save_addr and image_save_size, if proto == TFTPPUT
|
|
||||||
*
|
|
||||||
* @proto: command prototype
|
* @proto: command prototype
|
||||||
* @argc: number of arguments, include the command, which has already been
|
* @argc: number of arguments
|
||||||
* parsed
|
* @argv: command line arguments
|
||||||
* @argv: command line arguments, with argv[0] being the command
|
|
||||||
* @fnamep: set to the filename, if provided, else NULL
|
|
||||||
* @addrp: returns the load/save address, if any is provided, else it is
|
|
||||||
* left unchanged
|
|
||||||
* @sizep: returns the save size, if any is provided, else it is left
|
|
||||||
* unchanged
|
|
||||||
* Return: 0 on success
|
* Return: 0 on success
|
||||||
*/
|
*/
|
||||||
static int parse_args(enum proto_t proto, int argc, char *const argv[],
|
static int parse_args(enum proto_t proto, int argc, char *const argv[])
|
||||||
const char **fnamep, ulong *addrp, ulong *sizep)
|
|
||||||
{
|
{
|
||||||
ulong addr;
|
ulong addr;
|
||||||
char *end;
|
char *end;
|
||||||
|
|
||||||
*fnamep = NULL;
|
|
||||||
switch (argc) {
|
switch (argc) {
|
||||||
case 1:
|
case 1:
|
||||||
if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT)
|
if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* refresh bootfile name from env */
|
||||||
|
copy_filename(net_boot_file_name, env_get("bootfile"),
|
||||||
|
sizeof(net_boot_file_name));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -352,42 +343,48 @@ static int parse_args(enum proto_t proto, int argc, char *const argv[],
|
||||||
* mis-interpreted as a valid number.
|
* mis-interpreted as a valid number.
|
||||||
*/
|
*/
|
||||||
addr = hextoul(argv[1], &end);
|
addr = hextoul(argv[1], &end);
|
||||||
if (end == (argv[1] + strlen(argv[1])))
|
if (end == (argv[1] + strlen(argv[1]))) {
|
||||||
*addrp = addr;
|
image_load_addr = addr;
|
||||||
else
|
/* refresh bootfile name from env */
|
||||||
*fnamep = argv[1];
|
copy_filename(net_boot_file_name, env_get("bootfile"),
|
||||||
|
sizeof(net_boot_file_name));
|
||||||
|
} else {
|
||||||
|
net_boot_file_name_explicit = true;
|
||||||
|
copy_filename(net_boot_file_name, argv[1],
|
||||||
|
sizeof(net_boot_file_name));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) {
|
if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) {
|
||||||
if (parse_addr_size(argv, addrp, sizep))
|
if (parse_addr_size(argv))
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
*addrp = hextoul(argv[1], NULL);
|
image_load_addr = hextoul(argv[1], NULL);
|
||||||
*fnamep = argv[2];
|
net_boot_file_name_explicit = true;
|
||||||
|
copy_filename(net_boot_file_name, argv[2],
|
||||||
|
sizeof(net_boot_file_name));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CMD_TFTPPUT
|
||||||
case 4:
|
case 4:
|
||||||
if (IS_ENABLED(CONFIG_CMD_TFTPPUT)) {
|
if (parse_addr_size(argv))
|
||||||
if (parse_addr_size(argv, addrp, sizep))
|
|
||||||
return 1;
|
return 1;
|
||||||
*fnamep = argv[3];
|
net_boot_file_name_explicit = true;
|
||||||
|
copy_filename(net_boot_file_name, argv[3],
|
||||||
|
sizeof(net_boot_file_name));
|
||||||
break;
|
break;
|
||||||
}
|
#endif
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
|
static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
ulong addr, save_size;
|
|
||||||
bool fname_explicit;
|
|
||||||
const char *fname;
|
|
||||||
char *s;
|
char *s;
|
||||||
int rcode = 0;
|
int rcode = 0;
|
||||||
int size;
|
int size;
|
||||||
|
@ -395,10 +392,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
|
||||||
net_boot_file_name_explicit = false;
|
net_boot_file_name_explicit = false;
|
||||||
*net_boot_file_name = '\0';
|
*net_boot_file_name = '\0';
|
||||||
|
|
||||||
/* pre-set addr */
|
/* pre-set image_load_addr */
|
||||||
s = env_get("loadaddr");
|
s = env_get("loadaddr");
|
||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
addr = hextoul(s, NULL);
|
image_load_addr = hextoul(s, NULL);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_IPV6)) {
|
if (IS_ENABLED(CONFIG_IPV6)) {
|
||||||
use_ip6 = false;
|
use_ip6 = false;
|
||||||
|
@ -411,17 +408,12 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_args(proto, argc, argv, &fname, &addr, &save_size)) {
|
if (parse_args(proto, argc, argv)) {
|
||||||
bootstage_error(BOOTSTAGE_ID_NET_START);
|
bootstage_error(BOOTSTAGE_ID_NET_START);
|
||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fname) {
|
bootstage_mark(BOOTSTAGE_ID_NET_START);
|
||||||
fname_explicit = true;
|
|
||||||
} else {
|
|
||||||
fname_explicit = false;
|
|
||||||
fname = env_get("bootfile");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) {
|
if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) {
|
||||||
char *s, *e;
|
char *s, *e;
|
||||||
|
@ -436,10 +428,12 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size = netboot_run_(proto, addr, fname, save_size, fname_explicit,
|
size = net_loop(proto);
|
||||||
IS_ENABLED(CONFIG_IPV6) && use_ip6);
|
if (size < 0) {
|
||||||
if (size < 0)
|
bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
|
}
|
||||||
|
bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
|
||||||
|
|
||||||
/* net_loop ok, update environment */
|
/* net_loop ok, update environment */
|
||||||
netboot_update_env();
|
netboot_update_env();
|
||||||
|
|
|
@ -7,15 +7,11 @@
|
||||||
|
|
||||||
#define LOG_CATEGORY LOGC_BOOT
|
#define LOG_CATEGORY LOGC_BOOT
|
||||||
|
|
||||||
#include <bootm.h>
|
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <mapmem.h>
|
#include <mapmem.h>
|
||||||
#include <vsprintf.h>
|
#include <vsprintf.h>
|
||||||
#include <asm/zimage.h>
|
#include <asm/zimage.h>
|
||||||
|
|
||||||
/* Current state of the boot */
|
|
||||||
static struct bootm_info bmi;
|
|
||||||
|
|
||||||
static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
|
@ -24,8 +20,6 @@ static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
ulong base_addr;
|
ulong base_addr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
bootm_init(&bmi);
|
|
||||||
|
|
||||||
log_debug("argc %d:", argc);
|
log_debug("argc %d:", argc);
|
||||||
for (i = 0; i < argc; i++)
|
for (i = 0; i < argc; i++)
|
||||||
log_debug(" %s", argv[i]);
|
log_debug(" %s", argv[i]);
|
||||||
|
@ -41,7 +35,7 @@ static int do_zboot_start(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
base_addr = argc > 5 ? hextoul(argv[5], NULL) : 0;
|
base_addr = argc > 5 ? hextoul(argv[5], NULL) : 0;
|
||||||
cmdline = argc > 6 ? env_get(argv[6]) : NULL;
|
cmdline = argc > 6 ? env_get(argv[6]) : NULL;
|
||||||
|
|
||||||
zboot_start(&bmi, bzimage_addr, bzimage_size, initrd_addr, initrd_size,
|
zboot_start(bzimage_addr, bzimage_size, initrd_addr, initrd_size,
|
||||||
base_addr, cmdline);
|
base_addr, cmdline);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -52,7 +46,7 @@ static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = zboot_load(&bmi);
|
ret = zboot_load();
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -62,17 +56,16 @@ static int do_zboot_load(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
if (!bmi.base_ptr) {
|
if (!state.base_ptr) {
|
||||||
printf("base is not set: use 'zboot load' first\n");
|
printf("base is not set: use 'zboot load' first\n");
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
if (zboot_setup()) {
|
||||||
if (zboot_setup(&bmi)) {
|
|
||||||
puts("Setting up boot parameters failed ...\n");
|
puts("Setting up boot parameters failed ...\n");
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zboot_setup(&bmi))
|
if (zboot_setup())
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -81,7 +74,7 @@ static int do_zboot_setup(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_zboot_info(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
zboot_info(&bmi);
|
zboot_info();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +84,7 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = zboot_go(&bmi);
|
ret = zboot_go();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("Kernel returned! (err=%d)\n", ret);
|
printf("Kernel returned! (err=%d)\n", ret);
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
|
@ -103,13 +96,15 @@ static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_zboot_dump(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
{
|
{
|
||||||
|
struct boot_params *base_ptr = state.base_ptr;
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
bmi.base_ptr = (void *)hextoul(argv[1], NULL);
|
base_ptr = (void *)hextoul(argv[1], NULL);
|
||||||
if (!bmi.base_ptr) {
|
if (!base_ptr) {
|
||||||
printf("No zboot setup_base\n");
|
printf("No zboot setup_base\n");
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
zimage_dump(&bmi, true);
|
zimage_dump(base_ptr, true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +119,7 @@ U_BOOT_SUBCMDS(zboot,
|
||||||
U_BOOT_CMD_MKENT(dump, 2, 1, do_zboot_dump, "", ""),
|
U_BOOT_CMD_MKENT(dump, 2, 1, do_zboot_dump, "", ""),
|
||||||
)
|
)
|
||||||
|
|
||||||
static int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc,
|
int do_zboot_states(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[], int state_mask)
|
char *const argv[], int state_mask)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
|
@ -44,21 +44,6 @@ struct cmd_tbl;
|
||||||
* @argc: Number of arguments to the command (excluding the actual command).
|
* @argc: Number of arguments to the command (excluding the actual command).
|
||||||
* This is 0 if there are no arguments
|
* This is 0 if there are no arguments
|
||||||
* @argv: NULL-terminated list of arguments, or NULL if there are no arguments
|
* @argv: NULL-terminated list of arguments, or NULL if there are no arguments
|
||||||
*
|
|
||||||
* For zboot:
|
|
||||||
* @bzimage_addr: Address of the bzImage to boot, or 0 if the image has already
|
|
||||||
* been loaded and does not exist (as a cohesive whole) in memory
|
|
||||||
* @bzimage_size: Size of the bzImage, or 0 to detect this
|
|
||||||
* @initrd_addr: Address of the initial ramdisk, or 0 if none
|
|
||||||
* @initrd_size: Size of the initial ramdisk, or 0 if none
|
|
||||||
* @load_address: Address where the bzImage is moved before booting, either
|
|
||||||
* BZIMAGE_LOAD_ADDR or ZIMAGE_LOAD_ADDR
|
|
||||||
* This is set up when loading the zimage
|
|
||||||
* @base_ptr: Pointer to the boot parameters, typically at address
|
|
||||||
* DEFAULT_SETUP_BASE
|
|
||||||
* This is set up when loading the zimage
|
|
||||||
* @cmdline: Environment variable containing the 'override' command line, or
|
|
||||||
* NULL to use the one in the setup block
|
|
||||||
*/
|
*/
|
||||||
struct bootm_info {
|
struct bootm_info {
|
||||||
const char *addr_img;
|
const char *addr_img;
|
||||||
|
@ -69,39 +54,11 @@ struct bootm_info {
|
||||||
const char *cmd_name;
|
const char *cmd_name;
|
||||||
int argc;
|
int argc;
|
||||||
char *const *argv;
|
char *const *argv;
|
||||||
|
|
||||||
/* zboot items */
|
|
||||||
#ifdef CONFIG_X86
|
|
||||||
ulong bzimage_addr;
|
|
||||||
ulong bzimage_size;
|
|
||||||
ulong initrd_addr;
|
|
||||||
ulong initrd_size;
|
|
||||||
ulong load_address;
|
|
||||||
struct boot_params *base_ptr;
|
|
||||||
const char *cmdline;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* macro to allow setting fields in generic code */
|
|
||||||
#ifdef CONFIG_X86
|
|
||||||
#define bootm_x86_set(_bmi, _field, _val) (_bmi)->_field = (_val)
|
|
||||||
#else
|
|
||||||
#define bootm_x86_set(_bmi, _field, _val)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline ulong bootm_len(void)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_SYS_BOOTM_LEN
|
|
||||||
return CONFIG_SYS_BOOTM_LEN;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bootm_init() - Set up a bootm_info struct with useful defaults
|
* bootm_init() - Set up a bootm_info struct with useful defaults
|
||||||
*
|
*
|
||||||
* @bmi: Bootm information
|
|
||||||
*
|
|
||||||
* Set up the struct with default values for all members:
|
* Set up the struct with default values for all members:
|
||||||
* @boot_progress is set to true and @images is set to the global images
|
* @boot_progress is set to true and @images is set to the global images
|
||||||
* variable. Everything else is set to NULL except @argc which is 0
|
* variable. Everything else is set to NULL except @argc which is 0
|
||||||
|
@ -117,7 +74,7 @@ void bootm_init(struct bootm_info *bmi);
|
||||||
* - disabled interrupts.
|
* - disabled interrupts.
|
||||||
*
|
*
|
||||||
* @flag: Flags indicating what to do (BOOTM_STATE_...)
|
* @flag: Flags indicating what to do (BOOTM_STATE_...)
|
||||||
* @bmi: Bootm information
|
* bmi: Bootm information
|
||||||
* Return: 1 on error. On success the OS boots so this function does
|
* Return: 1 on error. On success the OS boots so this function does
|
||||||
* not return.
|
* not return.
|
||||||
*/
|
*/
|
||||||
|
@ -318,15 +275,6 @@ int bootm_process_cmdline_env(int flags);
|
||||||
/**
|
/**
|
||||||
* zboot_run() - Run through the various steps to boot a zimage
|
* zboot_run() - Run through the various steps to boot a zimage
|
||||||
*
|
*
|
||||||
* @bmi: Bootm information, with bzimage_size, initrd_addr, initrd_size and
|
|
||||||
* cmdline set up. If base_ptr is 0, then bzimage_addr must be set to the start
|
|
||||||
* of the bzImage. Otherwise base_ptr and load_address must be provided.
|
|
||||||
*/
|
|
||||||
int zboot_run(struct bootm_info *bmi);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* zboot_run_args() - Run through the various steps to boot a zimage
|
|
||||||
*
|
|
||||||
* Boot a zimage, given the component parts
|
* Boot a zimage, given the component parts
|
||||||
*
|
*
|
||||||
* @addr: Address where the bzImage is moved before booting, either
|
* @addr: Address where the bzImage is moved before booting, either
|
||||||
|
@ -341,7 +289,7 @@ int zboot_run(struct bootm_info *bmi);
|
||||||
* to use for booting
|
* to use for booting
|
||||||
* Return: -EFAULT on error (normally it does not return)
|
* Return: -EFAULT on error (normally it does not return)
|
||||||
*/
|
*/
|
||||||
int zboot_run_args(ulong addr, ulong size, ulong initrd, ulong initrd_size,
|
int zboot_run(ulong addr, ulong size, ulong initrd, ulong initrd_size,
|
||||||
ulong base, char *cmdline);
|
ulong base, char *cmdline);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -359,10 +307,11 @@ const char *zimage_get_kernel_version(struct boot_params *params,
|
||||||
*
|
*
|
||||||
* This shows all available information in a zimage that has been loaded.
|
* This shows all available information in a zimage that has been loaded.
|
||||||
*
|
*
|
||||||
* @bmi: Bootm information, with valid base_ptr
|
* @base_ptr: Pointer to the boot parameters, typically at address
|
||||||
|
* DEFAULT_SETUP_BASE
|
||||||
* @show_cmdline: true to show the full command line
|
* @show_cmdline: true to show the full command line
|
||||||
*/
|
*/
|
||||||
void zimage_dump(struct bootm_info *bmi, bool show_cmdline);
|
void zimage_dump(struct boot_params *base_ptr, bool show_cmdline);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bootm_boot_start() - Boot an image at the given address
|
* bootm_boot_start() - Boot an image at the given address
|
||||||
|
|
|
@ -244,7 +244,7 @@ enum image_type_t {
|
||||||
* New IDs *MUST* be appended at the end of the list and *NEVER*
|
* New IDs *MUST* be appended at the end of the list and *NEVER*
|
||||||
* inserted for backward compatibility.
|
* inserted for backward compatibility.
|
||||||
*/
|
*/
|
||||||
enum image_comp_t {
|
enum {
|
||||||
IH_COMP_NONE = 0, /* No Compression Used */
|
IH_COMP_NONE = 0, /* No Compression Used */
|
||||||
IH_COMP_GZIP, /* gzip Compression Used */
|
IH_COMP_GZIP, /* gzip Compression Used */
|
||||||
IH_COMP_BZIP2, /* bzip2 Compression Used */
|
IH_COMP_BZIP2, /* bzip2 Compression Used */
|
||||||
|
@ -598,13 +598,10 @@ int boot_get_setup(struct bootm_headers *images, uint8_t arch, ulong *setup_star
|
||||||
ulong *setup_len);
|
ulong *setup_len);
|
||||||
|
|
||||||
/* Image format types, returned by _get_format() routine */
|
/* Image format types, returned by _get_format() routine */
|
||||||
enum image_fmt_t {
|
#define IMAGE_FORMAT_INVALID 0x00
|
||||||
IMAGE_FORMAT_INVALID,
|
#define IMAGE_FORMAT_LEGACY 0x01 /* legacy image_header based format */
|
||||||
IMAGE_FORMAT_LEGACY, /* legacy image_header based format */
|
#define IMAGE_FORMAT_FIT 0x02 /* new, libfdt based format */
|
||||||
IMAGE_FORMAT_FIT, /* new, libfdt based format */
|
#define IMAGE_FORMAT_ANDROID 0x03 /* Android boot image */
|
||||||
IMAGE_FORMAT_ANDROID, /* Android boot image */
|
|
||||||
IMAGE_FORMAT_BOOTI, /* Arm64/RISC-V boot image */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* genimg_get_kernel_addr_fit() - Parse FIT specifier
|
* genimg_get_kernel_addr_fit() - Parse FIT specifier
|
||||||
|
@ -633,42 +630,9 @@ ulong genimg_get_kernel_addr_fit(const char *const img_addr,
|
||||||
const char **fit_uname_kernel);
|
const char **fit_uname_kernel);
|
||||||
|
|
||||||
ulong genimg_get_kernel_addr(char * const img_addr);
|
ulong genimg_get_kernel_addr(char * const img_addr);
|
||||||
|
int genimg_get_format(const void *img_addr);
|
||||||
/**
|
|
||||||
* genimg_get_format - get image format type
|
|
||||||
* @img_addr: image start address
|
|
||||||
* Return: image format type or IMAGE_FORMAT_INVALID if no image is present
|
|
||||||
*
|
|
||||||
* genimg_get_format() checks whether provided address points to a valid
|
|
||||||
* legacy or FIT image.
|
|
||||||
*
|
|
||||||
* New uImage format and FDT blob are based on a libfdt. FDT blob
|
|
||||||
* may be passed directly or embedded in a FIT image. In both situations
|
|
||||||
* genimg_get_format() must be able to dectect libfdt header.
|
|
||||||
*/
|
|
||||||
enum image_fmt_t genimg_get_format(const void *img_addr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* genimg_get_format_comp() - Like genimg_get_format() but adds compressed booti
|
|
||||||
*
|
|
||||||
* If a compressed file is detected (with image_decomp_type()) and
|
|
||||||
* CONFIG_CMD_BOOTI is enabled, then this returns IMAGE_FORMAT_BOOTI
|
|
||||||
*
|
|
||||||
* @img_addr: image start address
|
|
||||||
* Return: image format type or IMAGE_FORMAT_INVALID if no image is present
|
|
||||||
*/
|
|
||||||
enum image_fmt_t genimg_get_format_comp(const void *img_addr);
|
|
||||||
|
|
||||||
int genimg_has_config(struct bootm_headers *images);
|
int genimg_has_config(struct bootm_headers *images);
|
||||||
|
|
||||||
/**
|
|
||||||
* booti_is_valid() - Check if an image appears to be an Arm64 image
|
|
||||||
*
|
|
||||||
* @img: Pointer to image
|
|
||||||
* Return: true if the image has the Arm64 magic
|
|
||||||
*/
|
|
||||||
bool booti_is_valid(const void *img);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* boot_get_fpga() - Locate the FPGA image
|
* boot_get_fpga() - Locate the FPGA image
|
||||||
*
|
*
|
||||||
|
|
|
@ -475,36 +475,6 @@ int net_init(void);
|
||||||
enum proto_t;
|
enum proto_t;
|
||||||
int net_loop(enum proto_t protocol);
|
int net_loop(enum proto_t protocol);
|
||||||
|
|
||||||
/* internal function: do not use! */
|
|
||||||
int netboot_run_(enum proto_t proto, ulong addr, const char *fname, ulong size,
|
|
||||||
bool fname_explicit, bool ipv6);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* netboot_run() - Run a network operation
|
|
||||||
*
|
|
||||||
* The following proto values are NOT supported:
|
|
||||||
* PING, since net_ping_ip cannot be set
|
|
||||||
* NETCONS, since its parameters cannot bet set
|
|
||||||
* RS, since first_call cannot be set, along with perhaps other things
|
|
||||||
* UDP, since udp_ops cannot be set
|
|
||||||
* DNS, since net_dns_resolve and net_dns_env_var cannot be set
|
|
||||||
* WGET, since DNS must be done first and that is not supported
|
|
||||||
* DHCP6, since the required parameters cannot be passed in
|
|
||||||
*
|
|
||||||
* To support one of these, either add the required arguments or perhaps a
|
|
||||||
* separate function and a struct to hold the information.
|
|
||||||
*
|
|
||||||
* @proto: Operation to run: TFTPGET, FASTBOOT_UDP, FASTBOOT_TCP, BOOTP,
|
|
||||||
* TFTPPUT, RARP, NFS, DHCP
|
|
||||||
* @addr: Load/save address
|
|
||||||
* @fname: Filename
|
|
||||||
* @size: Save size (not used for TFTPGET)
|
|
||||||
* @ipv6: true to use IPv6, false to use IPv4
|
|
||||||
* Return 0 on success, else -ve error code
|
|
||||||
*/
|
|
||||||
int netboot_run(enum proto_t proto, ulong addr, const char *fname, ulong size,
|
|
||||||
bool ipv6);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dhcp_run() - Run DHCP on the current ethernet device
|
* dhcp_run() - Run DHCP on the current ethernet device
|
||||||
*
|
*
|
||||||
|
|
44
net/net.c
44
net/net.c
|
@ -775,50 +775,6 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int netboot_run_(enum proto_t proto, ulong addr, const char *fname, ulong size,
|
|
||||||
bool fname_explicit, bool ipv6)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
bootstage_mark(BOOTSTAGE_ID_NET_START);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For now we use the global variables as that is the only way to
|
|
||||||
* control the network stack. At some point, perhaps, the state could be
|
|
||||||
* in a struct
|
|
||||||
*/
|
|
||||||
if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT)
|
|
||||||
image_save_addr = addr;
|
|
||||||
else
|
|
||||||
image_load_addr = addr;
|
|
||||||
|
|
||||||
net_boot_file_name_explicit = fname_explicit;
|
|
||||||
copy_filename(net_boot_file_name, fname, sizeof(net_boot_file_name));
|
|
||||||
if (IS_ENABLED(CONFIG_IPV6))
|
|
||||||
use_ip6 = ipv6;
|
|
||||||
if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) {
|
|
||||||
image_save_addr = addr;
|
|
||||||
image_save_size = size;
|
|
||||||
} else {
|
|
||||||
image_load_addr = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = net_loop(proto);
|
|
||||||
if (ret < 0) {
|
|
||||||
bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int netboot_run(enum proto_t proto, ulong addr, const char *fname, ulong size,
|
|
||||||
bool ipv6)
|
|
||||||
{
|
|
||||||
return netboot_run_(proto, addr, fname, size, true, ipv6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
static void start_again_timeout_handler(void)
|
static void start_again_timeout_handler(void)
|
||||||
|
|
Loading…
Add table
Reference in a new issue