From 6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:29:51 +0200 Subject: Adding upstream version 2.06. Signed-off-by: Daniel Baumann --- grub-core/kern/uboot/hw.c | 112 ++++++++++++++++ grub-core/kern/uboot/init.c | 172 ++++++++++++++++++++++++ grub-core/kern/uboot/uboot.c | 307 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 591 insertions(+) create mode 100644 grub-core/kern/uboot/hw.c create mode 100644 grub-core/kern/uboot/init.c create mode 100644 grub-core/kern/uboot/uboot.c (limited to 'grub-core/kern/uboot') diff --git a/grub-core/kern/uboot/hw.c b/grub-core/kern/uboot/hw.c new file mode 100644 index 0000000..272b83b --- /dev/null +++ b/grub-core/kern/uboot/hw.c @@ -0,0 +1,112 @@ +/* hw.c - U-Boot hardware discovery */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +grub_addr_t start_of_ram; + +/* + * grub_uboot_probe_memory(): + * Queries U-Boot for available memory regions. + * + * Sets up heap near the image in memory and sets up "start_of_ram". + */ +void +grub_uboot_mm_init (void) +{ + struct sys_info *si = grub_uboot_get_sys_info (); + + grub_mm_init_region ((void *) grub_modules_get_end (), + GRUB_KERNEL_MACHINE_HEAP_SIZE); + + if (si && (si->mr_no != 0)) + { + int i; + start_of_ram = GRUB_UINT_MAX; + + for (i = 0; i < si->mr_no; i++) + if ((si->mr[i].flags & MR_ATTR_MASK) == MR_ATTR_DRAM) + if (si->mr[i].start < start_of_ram) + start_of_ram = si->mr[i].start; + } +} + +/* + * grub_uboot_probe_hardware(): + */ +grub_err_t +grub_uboot_probe_hardware (void) +{ + int devcount, i; + + devcount = grub_uboot_dev_enum (); + grub_dprintf ("init", "%d devices found\n", devcount); + + for (i = 0; i < devcount; i++) + { + struct device_info *devinfo = grub_uboot_dev_get (i); + + grub_dprintf ("init", "device handle: %d\n", i); + grub_dprintf ("init", " cookie\t= 0x%08x\n", + (grub_uint32_t) devinfo->cookie); + + if (devinfo->type & DEV_TYP_STOR) + { + grub_dprintf ("init", " type\t\t= DISK\n"); + grub_ubootdisk_register (devinfo); + } + else if (devinfo->type & DEV_TYP_NET) + { + /* Dealt with in ubootnet module. */ + grub_dprintf ("init", " type\t\t= NET (not supported yet)\n"); + } + else + { + grub_dprintf ("init", "%s: unknown device type", __FUNCTION__); + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_machine_mmap_iterate (grub_memory_hook_t hook, void *hook_data) +{ + int i; + struct sys_info *si = grub_uboot_get_sys_info (); + + if (!si || (si->mr_no < 1)) + return GRUB_ERR_BUG; + + /* Iterate and call `hook'. */ + for (i = 0; i < si->mr_no; i++) + if ((si->mr[i].flags & MR_ATTR_MASK) == MR_ATTR_DRAM) + hook (si->mr[i].start, si->mr[i].size, GRUB_MEMORY_AVAILABLE, + hook_data); + + return GRUB_ERR_NONE; +} diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c new file mode 100644 index 0000000..3e33864 --- /dev/null +++ b/grub-core/kern/uboot/init.c @@ -0,0 +1,172 @@ +/* init.c - generic U-Boot initialization and finalization */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char __bss_start[]; +extern char _end[]; +extern grub_size_t grub_total_module_size; +static unsigned long timer_start; + +void +grub_exit (void) +{ + grub_uboot_return (0); +} + +static grub_uint64_t +uboot_timer_ms (void) +{ + static grub_uint32_t last = 0, high = 0; + grub_uint32_t cur = grub_uboot_get_timer (timer_start); + if (cur < last) + high++; + last = cur; + return (((grub_uint64_t) high) << 32) | cur; +} + +#ifdef __arm__ +static grub_uint64_t +rpi_timer_ms (void) +{ + static grub_uint32_t last = 0, high = 0; + grub_uint32_t cur = *(volatile grub_uint32_t *) 0x20003004; + if (cur < last) + high++; + last = cur; + return grub_divmod64 ((((grub_uint64_t) high) << 32) | cur, 1000, 0); +} +#endif + +void +grub_machine_init (void) +{ + int ver; + + /* First of all - establish connection with U-Boot */ + ver = grub_uboot_api_init (); + if (!ver) + { + /* Don't even have a console to log errors to... */ + grub_exit (); + } + else if (ver > API_SIG_VERSION) + { + /* Try to print an error message */ + grub_uboot_puts ("invalid U-Boot API version\n"); + } + + /* Initialize the console so that GRUB can display messages. */ + grub_console_init_early (); + + /* Enumerate memory and initialize the memory management system. */ + grub_uboot_mm_init (); + + /* Should be earlier but it needs memalign. */ +#ifdef __arm__ + grub_arm_enable_caches_mmu (); +#endif + + grub_dprintf ("init", "__bss_start: %p\n", __bss_start); + grub_dprintf ("init", "_end: %p\n", _end); + grub_dprintf ("init", "grub_modbase: %p\n", (void *) grub_modbase); + grub_dprintf ("init", "grub_modules_get_end(): %p\n", + (void *) grub_modules_get_end ()); + + /* Initialise full terminfo support */ + grub_console_init_lately (); + + /* Enumerate uboot devices */ + grub_uboot_probe_hardware (); + + /* Initialise timer */ +#ifdef __arm__ + if (grub_uboot_get_machine_type () == GRUB_ARM_MACHINE_TYPE_RASPBERRY_PI) + { + grub_install_get_time_ms (rpi_timer_ms); + } + else +#endif + { + timer_start = grub_uboot_get_timer (0); + grub_install_get_time_ms (uboot_timer_ms); + } + + /* Initialize */ + grub_ubootdisk_init (); +} + + +void +grub_machine_fini (int flags __attribute__ ((unused))) +{ +} + +/* + * grub_machine_get_bootlocation(): + * Called from kern/main.c, which expects a device name (minus parentheses) + * and a filesystem path back, if any are known. + * Any returned values must be pointers to dynamically allocated strings. + */ +void +grub_machine_get_bootlocation (char **device, char **path) +{ + char *tmp; + + tmp = grub_uboot_env_get ("grub_bootdev"); + if (tmp) + { + *device = grub_strdup (tmp); + if (*device == NULL) + return; + } + else + *device = NULL; + + tmp = grub_uboot_env_get ("grub_bootpath"); + if (tmp) + { + *path = grub_strdup (tmp); + if (*path == NULL) + return; + } + else + *path = NULL; +} + +void +grub_uboot_fini (void) +{ + grub_ubootdisk_fini (); + grub_console_fini (); +} diff --git a/grub-core/kern/uboot/uboot.c b/grub-core/kern/uboot/uboot.c new file mode 100644 index 0000000..aac8f9a --- /dev/null +++ b/grub-core/kern/uboot/uboot.c @@ -0,0 +1,307 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +/* + * The main syscall entry point is not reentrant, only one call is + * serviced until finished. + * + * int syscall(int call, int *retval, ...) + * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t); + * + * call: syscall number + * + * retval: points to the return value placeholder, this is the place the + * syscall puts its return value, if NULL the caller does not + * expect a return value + * + * ... syscall arguments (variable number) + * + * returns: 0 if the call not found, 1 if serviced + */ + +extern int grub_uboot_syscall (int, int *, ...); + +static struct sys_info uboot_sys_info; +static struct mem_region uboot_mem_info[5]; +static struct device_info * devices; +static int num_devices; + + +/* + * All functions below are wrappers around the grub_uboot_syscall() function + */ + +int +grub_uboot_getc (void) +{ + int c; + if (!grub_uboot_syscall (API_GETC, NULL, &c)) + return -1; + + return c; +} + +int +grub_uboot_tstc (void) +{ + int c; + if (!grub_uboot_syscall (API_TSTC, NULL, &c)) + return -1; + + return c; +} + +void +grub_uboot_putc (int c) +{ + grub_uboot_syscall (API_PUTC, NULL, &c); +} + +void +grub_uboot_puts (const char *s) +{ + grub_uboot_syscall (API_PUTS, NULL, s); +} + +void +grub_uboot_reset (void) +{ + grub_uboot_syscall (API_RESET, NULL, 0); +} + +struct sys_info * +grub_uboot_get_sys_info (void) +{ + int retval; + + grub_memset (&uboot_sys_info, 0, sizeof (uboot_sys_info)); + grub_memset (&uboot_mem_info, 0, sizeof (uboot_mem_info)); + uboot_sys_info.mr = uboot_mem_info; + uboot_sys_info.mr_no = sizeof (uboot_mem_info) / sizeof (struct mem_region); + + if (grub_uboot_syscall (API_GET_SYS_INFO, &retval, &uboot_sys_info)) + if (retval == 0) + return &uboot_sys_info; + + return NULL; +} + +void +grub_uboot_udelay (grub_uint32_t usec) +{ + grub_uboot_syscall (API_UDELAY, NULL, &usec); +} + +grub_uint32_t +grub_uboot_get_timer (grub_uint32_t base) +{ + grub_uint32_t current; + + if (!grub_uboot_syscall (API_GET_TIMER, NULL, ¤t, &base)) + return 0; + + return current; +} + +int +grub_uboot_dev_enum (void) +{ + struct device_info * enum_devices; + int num_enum_devices, max_devices; + + if (num_devices) + return num_devices; + + max_devices = 2; + enum_devices = grub_calloc (max_devices, sizeof(struct device_info)); + if (!enum_devices) + return 0; + + /* + * The API_DEV_ENUM call starts a fresh enumeration when passed a + * struct device_info with a NULL cookie, and then depends on having + * the previously enumerated device cookie "seeded" into the target + * structure. + */ + + enum_devices[0].cookie = NULL; + num_enum_devices = 0; + + if (grub_uboot_syscall (API_DEV_ENUM, NULL, + &enum_devices[num_enum_devices]) == 0) + goto error; + + num_enum_devices++; + + while (enum_devices[num_enum_devices - 1].cookie != NULL) + { + if (num_enum_devices == max_devices) + { + struct device_info *tmp; + int new_max; + new_max = max_devices * 2; + tmp = grub_realloc (enum_devices, + sizeof (struct device_info) * new_max); + if (!tmp) + { + /* Failed to realloc, so return what we have */ + break; + } + enum_devices = tmp; + max_devices = new_max; + } + + enum_devices[num_enum_devices].cookie = + enum_devices[num_enum_devices - 1].cookie; + if (grub_uboot_syscall (API_DEV_ENUM, NULL, + &enum_devices[num_enum_devices]) == 0) + goto error; + + if (enum_devices[num_enum_devices].cookie == NULL) + break; + + num_enum_devices++; + } + + devices = enum_devices; + return num_devices = num_enum_devices; + + error: + grub_free (enum_devices); + return 0; +} + +#define VALID_DEV(x) (((x) < num_devices) && ((x) >= 0)) +#define OPEN_DEV(x) ((x->state == DEV_STA_OPEN)) + +struct device_info * +grub_uboot_dev_get (int index) +{ + if (VALID_DEV (index)) + return &devices[index]; + + return NULL; +} + + +int +grub_uboot_dev_open (struct device_info *dev) +{ + int retval; + + if (!grub_uboot_syscall (API_DEV_OPEN, &retval, dev)) + return -1; + + return retval; +} + +int +grub_uboot_dev_close (struct device_info *dev) +{ + int retval; + + if (!grub_uboot_syscall (API_DEV_CLOSE, &retval, dev)) + return -1; + + return retval; +} + + +int +grub_uboot_dev_read (struct device_info *dev, void *buf, grub_size_t blocks, + grub_uint32_t start, grub_size_t * real_blocks) +{ + int retval; + + if (!OPEN_DEV (dev)) + return -1; + + if (!grub_uboot_syscall (API_DEV_READ, &retval, dev, buf, + &blocks, &start, real_blocks)) + return -1; + + return retval; +} + +int +grub_uboot_dev_write (struct device_info *dev, const void *buf, + grub_size_t blocks, grub_uint32_t start) +{ + int retval; + + if (!OPEN_DEV (dev)) + return -1; + + if (!grub_uboot_syscall (API_DEV_WRITE, &retval, dev, buf, + &blocks, &start)) + return -1; + + return retval; +} + +int +grub_uboot_dev_recv (struct device_info *dev, void *buf, + int size, int *real_size) +{ + int retval; + + if (!OPEN_DEV (dev)) + return -1; + + if (!grub_uboot_syscall (API_DEV_READ, &retval, dev, buf, &size, real_size)) + return -1; + + return retval; + +} + +int +grub_uboot_dev_send (struct device_info *dev, void *buf, int size) +{ + int retval; + + if (!OPEN_DEV (dev)) + return -1; + + if (!grub_uboot_syscall (API_DEV_WRITE, &retval, dev, buf, &size)) + return -1; + + return retval; +} + +char * +grub_uboot_env_get (const char *name) +{ + char *value; + + if (!grub_uboot_syscall (API_ENV_GET, NULL, name, &value)) + return NULL; + + return value; +} + +void +grub_uboot_env_set (const char *name, const char *value) +{ + grub_uboot_syscall (API_ENV_SET, NULL, name, value); +} -- cgit v1.2.3