From: Heiher <r...@hev.cc> --- grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 3 + grub-core/kern/mips64/efi/init.c | 11 +- grub-core/kern/mips64/efi/loongson.c | 47 ++++ grub-core/lib/mips64/efi/loongson.c | 424 ++++++++++++++++++++++++++++++++ grub-core/lib/mips64/efi/loongson_asm.S | 61 +++++ grub-core/loader/mips64/linux.c | 75 +++++- include/grub/loader.h | 1 + include/grub/mips64/efi/loongson.h | 258 +++++++++++++++++++ 9 files changed, 877 insertions(+), 4 deletions(-) create mode 100644 grub-core/kern/mips64/efi/loongson.c create mode 100644 grub-core/lib/mips64/efi/loongson.c create mode 100644 grub-core/lib/mips64/efi/loongson_asm.S create mode 100644 include/grub/mips64/efi/loongson.h
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 5512f274f..3c5da3f9a 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -220,6 +220,7 @@ if COND_mips64_efi KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loongson.h endif if COND_powerpc_ieee1275 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 58009672b..6db00531f 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -272,6 +272,9 @@ kernel = { mips64 = kern/mips64/cache.S; mips64 = kern/generic/rtc_get_time_ms.c; mips64_efi = kern/mips64/efi/init.c; + mips64_efi = kern/mips64/efi/loongson.c; + mips64_efi = lib/mips64/efi/loongson.c; + mips64_efi = lib/mips64/efi/loongson_asm.S; powerpc_ieee1275 = kern/powerpc/cache.S; powerpc_ieee1275 = kern/powerpc/dl.c; diff --git a/grub-core/kern/mips64/efi/init.c b/grub-core/kern/mips64/efi/init.c index 074736db9..c3e4371ac 100644 --- a/grub-core/kern/mips64/efi/init.c +++ b/grub-core/kern/mips64/efi/init.c @@ -24,14 +24,17 @@ #include <grub/cpu/time.h> #include <grub/efi/efi.h> #include <grub/loader.h> +#include <grub/machine/loongson.h> void grub_machine_init (void) { grub_efi_init (); - - /* FIXME: Get cpuclock from EFI. */ - grub_timer_init (1000000000U); + if (grub_efi_is_loongson ()) + grub_efi_loongson_init (); + else + /* FIXME: Get cpuclock from EFI. */ + grub_timer_init (1000000000U); } void @@ -40,5 +43,7 @@ grub_machine_fini (int flags) if (!(flags & GRUB_LOADER_FLAG_NORETURN)) return; + if (grub_efi_is_loongson ()) + grub_efi_loongson_fini (flags); grub_efi_fini (); } diff --git a/grub-core/kern/mips64/efi/loongson.c b/grub-core/kern/mips64/efi/loongson.c new file mode 100644 index 000000000..dfbceba6a --- /dev/null +++ b/grub-core/kern/mips64/efi/loongson.c @@ -0,0 +1,47 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/efi/efi.h> +#include <grub/cpu/time.h> +#include <grub/loader.h> +#include <grub/machine/loongson.h> + +void +grub_efi_loongson_init (void) +{ + grub_efi_loongson_smbios_table *smbios_table; + grub_efi_loongson_cpu_info *cpu_info; + + smbios_table = grub_efi_loongson_get_smbios_table (); + if (!smbios_table) + grub_fatal ("cannot found Loongson SMBIOS!"); + + cpu_info = (grub_efi_loongson_cpu_info *) smbios_table->lp.cpu_offset; + grub_dprintf ("loongson", "cpu clock %u\n", cpu_info->cpu_clock_freq); + + grub_timer_init (cpu_info->cpu_clock_freq); + + grub_efi_loongson_alloc_boot_params (); +} + +void +grub_efi_loongson_fini (int flags) +{ + if (!(flags & GRUB_LOADER_FLAG_LOONGSON_BOOT_PARAMS_NOFREE)) + grub_efi_loongson_free_boot_params (); +} diff --git a/grub-core/lib/mips64/efi/loongson.c b/grub-core/lib/mips64/efi/loongson.c new file mode 100644 index 000000000..6f734bd1f --- /dev/null +++ b/grub-core/lib/mips64/efi/loongson.c @@ -0,0 +1,424 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/mm.h> +#include <grub/cache.h> +#include <grub/efi/efi.h> +#include <grub/cpu/efi/memory.h> +#include <grub/cpu/memory.h> +#include <grub/machine/loongson.h> + +#define loongson_params (&loongson_boot_params->boot_params.efi.smbios.lp) +#define loongson_boot_params_size ALIGN_UP (sizeof (*loongson_boot_params), 8) +#define loongson_reset_code_size (&grub_efi_loongson_reset_end - &grub_efi_loongson_reset_start) + +extern grub_uint8_t grub_efi_loongson_reset_start; +extern grub_uint8_t grub_efi_loongson_reset_end; + +static struct +{ + grub_efi_loongson_boot_params boot_params; + grub_efi_loongson_memory_map memory_map; + grub_efi_loongson_cpu_info cpu_info; + grub_efi_loongson_system_info system_info; + grub_efi_loongson_irq_src_routing_table irq_src_routing_table; + grub_efi_loongson_interface_info interface_info; + grub_efi_loongson_special_attribute special_attribute; + grub_efi_loongson_board_devices board_devices; +} GRUB_PACKED +* loongson_boot_params; + +static void +grub_efi_loongson_init_reset_system (void) +{ + grub_efi_loongson_boot_params *boot_params; + grub_uint8_t *reset_code_addr = (grub_uint8_t *) loongson_boot_params + + loongson_boot_params_size; + + boot_params = &loongson_boot_params->boot_params; + grub_efi_loongson_reset_system_addr = + (grub_uint64_t) grub_efi_system_table->runtime_services->reset_system; + grub_memcpy (reset_code_addr, &grub_efi_loongson_reset_start, loongson_reset_code_size); + grub_arch_sync_caches (reset_code_addr, loongson_reset_code_size); + + boot_params->reset_system.reset_cold = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_cold - + (grub_uint64_t) &grub_efi_loongson_reset_start); + boot_params->reset_system.reset_warm = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_warm - + (grub_uint64_t) &grub_efi_loongson_reset_start); + boot_params->reset_system.shutdown = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_shutdown - + (grub_uint64_t) &grub_efi_loongson_reset_start); + boot_params->reset_system.do_suspend = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_suspend - + (grub_uint64_t) &grub_efi_loongson_reset_start); +} + +static void +grub_efi_loongson_init_smbios (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_smbios_table *dst = &loongson_boot_params->boot_params.efi.smbios; + + dst->vers = smbios_table->vers; + dst->vga_bios = smbios_table->vga_bios; +} + +static void +grub_efi_loongson_init_cpu_info (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_cpu_info *src = (void *) smbios_table->lp.cpu_offset; + grub_efi_loongson_cpu_info *dst = &loongson_boot_params->cpu_info; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_cpu_info)); + loongson_params->cpu_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_system_info (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_system_info *src = (void *) smbios_table->lp.system_offset; + grub_efi_loongson_system_info *dst = &loongson_boot_params->system_info; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_system_info)); + loongson_params->system_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_irq_src_routing_table (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_irq_src_routing_table *src = (void *) smbios_table->lp.irq_offset; + grub_efi_loongson_irq_src_routing_table *dst = &loongson_boot_params->irq_src_routing_table; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_irq_src_routing_table)); + loongson_params->irq_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_interface_info (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_interface_info *src = (void *) smbios_table->lp.interface_offset; + grub_efi_loongson_interface_info *dst = &loongson_boot_params->interface_info; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_interface_info)); + loongson_params->interface_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_special_attribute (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_special_attribute *src = (void *) smbios_table->lp.special_offset; + grub_efi_loongson_special_attribute *dst = &loongson_boot_params->special_attribute; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_special_attribute)); + loongson_params->special_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_board_devices (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_board_devices *src = (void *) smbios_table->lp.boarddev_table_offset; + grub_efi_loongson_board_devices *dst = &loongson_boot_params->board_devices; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_board_devices)); + loongson_params->boarddev_table_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +#define ADD_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) + +static void +grub_efi_loongson_init_memory_map (grub_efi_loongson_smbios_table *smbios_table, + grub_efi_memory_descriptor_t *mmap_buf, + grub_efi_uintn_t mmap_size, + grub_efi_uintn_t desc_size) +{ + grub_efi_loongson_memory_map *src = (void *) smbios_table->lp.memory_offset; + grub_efi_loongson_memory_map *dst = &loongson_boot_params->memory_map; + grub_efi_memory_descriptor_t *mmap_end; + grub_efi_memory_descriptor_t *desc; + grub_efi_memory_descriptor_t *desc_next; + grub_efi_uint32_t mem_types_reserved[] = + { + 1, // GRUB_EFI_RESERVED_MEMORY_TYPE + 0, // GRUB_EFI_LOADER_CODE + 0, // GRUB_EFI_LOADER_DATA + 0, // GRUB_EFI_BOOT_SERVICES_CODE + 0, // GRUB_EFI_BOOT_SERVICES_DATA + 1, // GRUB_EFI_RUNTIME_SERVICES_CODE + 1, // GRUB_EFI_RUNTIME_SERVICES_DATA + 0, // GRUB_EFI_CONVENTIONAL_MEMORY + 1, // GRUB_EFI_UNUSABLE_MEMORY + 0, // GRUB_EFI_ACPI_RECLAIM_MEMORY + 0, // GRUB_EFI_ACPI_MEMORY_NVS + 1, // GRUB_EFI_MEMORY_MAPPED_IO + 1, // GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE + 1, // GRUB_EFI_PAL_CODE + 1, // GRUB_EFI_PERSISTENT_MEMORY + }; + grub_uint32_t need_sort = 1; + + if (!src) + return; + + dst->vers = src->vers; + dst->nr_map = 0; + dst->mem_freq = src->mem_freq; + loongson_params->memory_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; + + if (!mmap_buf || !mmap_size || !desc_size) + return; + + mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); + + /* drop reserved */ + for (desc = mmap_buf, + desc_next = desc; + desc < mmap_end; + desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) + { + desc->type = mem_types_reserved[desc->type]; + if (desc->type) + continue; + + if (desc != desc_next) + *desc_next = *desc; + desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size); + } + mmap_end = desc_next; + + /* sort: low -> high */ + while (need_sort) + { + need_sort = 0; + + for (desc = mmap_buf, + desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + (desc < mmap_end) && (desc_next < mmap_end); + desc = desc_next, + desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) + { + grub_efi_memory_descriptor_t tmp; + + if (desc->physical_start <= desc_next->physical_start) + continue; + + tmp = *desc; + *desc = *desc_next; + *desc_next = tmp; + need_sort = 1; + } + } + + /* combine continuous memory map */ + for (desc = mmap_buf, + desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + desc_next < mmap_end; + desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size)) + { + grub_efi_physical_address_t prev_end = desc->physical_start + (desc->num_pages << 12); + + if (prev_end == desc_next->physical_start) + { + desc->num_pages += desc_next->num_pages; + continue; + } + + desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + grub_memcpy (desc, desc_next, desc_size); + } + mmap_end = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + + /* write to loongson memory map */ + for (desc = mmap_buf; + desc < mmap_end; + desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) + { + grub_efi_physical_address_t physical_start = grub_vtop ((void *) desc->physical_start); + grub_efi_physical_address_t physical_end = physical_start + (desc->num_pages << 12); + + physical_start = ALIGN_UP (physical_start, 0x100000); + physical_end = ALIGN_DOWN (physical_end, 0x100000); + + if (physical_start >= physical_end || (physical_end - physical_start) < 0x100000) + continue; + + dst->map[dst->nr_map].node_id = (desc->physical_start >> 44) & 0xf; + dst->map[dst->nr_map].mem_type = (physical_end <= 0x10000000) ? + GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW : + GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH; + dst->map[dst->nr_map].mem_start = physical_start; + dst->map[dst->nr_map].mem_size = (physical_end - physical_start) >> 20; + + grub_dprintf ("loongson", "memory map %03u: 0x%016lx 0x%016lx @ %u\n", + dst->nr_map, physical_start, physical_end - physical_start, + dst->map[dst->nr_map].node_id); + + dst->nr_map ++; + } +} + +#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) +#define SUB_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) - (size))) + +void +grub_efi_loongson_alloc_boot_params (void) +{ + grub_efi_memory_descriptor_t *mmap_buf; + grub_efi_memory_descriptor_t *mmap_end; + grub_efi_memory_descriptor_t *desc; + grub_efi_uintn_t mmap_size; + grub_efi_uintn_t desc_size; + grub_efi_physical_address_t address; + grub_efi_allocate_type_t type; + grub_efi_uintn_t pages; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + int mm_status; + + type = GRUB_EFI_ALLOCATE_ADDRESS; + pages = BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size); + + mmap_size = (1 << 12); + mmap_buf = grub_malloc (mmap_size); + if (!mmap_buf) + grub_fatal ("out of memory!"); + + mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); + if (mm_status == 0) + { + grub_free (mmap_buf); + mmap_size += desc_size * 32; + + mmap_buf = grub_malloc (mmap_size); + if (!mmap_buf) + grub_fatal ("out of memory!"); + + mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); + } + + if (mm_status < 0) + grub_fatal ("cannot get memory map!"); + + mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); + + for (desc = SUB_MEMORY_DESCRIPTOR (mmap_end, desc_size); + desc >= mmap_buf; + desc = SUB_MEMORY_DESCRIPTOR (desc, desc_size)) + { + if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) + continue; + if (desc->physical_start >= GRUB_EFI_MAX_USABLE_ADDRESS) + continue; + if (desc->num_pages < pages) + continue; + + address = desc->physical_start; + break; + } + + grub_free (mmap_buf); + + b = grub_efi_system_table->boot_services; + status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address); + if (status != GRUB_EFI_SUCCESS) + grub_fatal ("cannot allocate Loongson boot parameters!"); + + loongson_boot_params = (void *) ((grub_addr_t) address); +} + +void +grub_efi_loongson_free_boot_params (void) +{ + grub_efi_free_pages ((grub_addr_t) loongson_boot_params, + BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size)); +} + +grub_efi_loongson_smbios_table * +grub_efi_loongson_get_smbios_table (void) +{ + static grub_efi_loongson_smbios_table *smbios_table; + grub_efi_configuration_table_t *tables; + grub_efi_guid_t smbios_guid = GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID; + unsigned int i; + + if (smbios_table) + return smbios_table; + + /* Look for Loongson SMBIOS in UEFI config tables. */ + tables = grub_efi_system_table->configuration_table; + + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + if (grub_memcmp (&tables[i].vendor_guid, &smbios_guid, sizeof (smbios_guid)) == 0) + { + smbios_table = tables[i].vendor_table; + grub_dprintf ("loongson", "found registered SMBIOS @ %p\n", smbios_table); + break; + } + + return smbios_table; +} + +int +grub_efi_is_loongson (void) +{ + return grub_efi_loongson_get_smbios_table () ? 1 : 0; +} + +grub_efi_loongson_boot_params * +grub_efi_loongson_get_boot_params (grub_efi_memory_descriptor_t *mmap_buf, + grub_efi_uintn_t mmap_size, + grub_efi_uintn_t desc_size) +{ + grub_efi_loongson_smbios_table *smbios_table; + + smbios_table = grub_efi_loongson_get_smbios_table (); + if (!smbios_table) + grub_fatal ("cannot found Loongson SMBIOS!"); + + grub_efi_loongson_init_reset_system (); + grub_efi_loongson_init_smbios (smbios_table); + grub_efi_loongson_init_cpu_info (smbios_table); + grub_efi_loongson_init_system_info (smbios_table); + grub_efi_loongson_init_irq_src_routing_table (smbios_table); + grub_efi_loongson_init_interface_info (smbios_table); + grub_efi_loongson_init_special_attribute (smbios_table); + grub_efi_loongson_init_board_devices (smbios_table); + grub_efi_loongson_init_memory_map (smbios_table, mmap_buf, mmap_size, desc_size); + + return &loongson_boot_params->boot_params; +} diff --git a/grub-core/lib/mips64/efi/loongson_asm.S b/grub-core/lib/mips64/efi/loongson_asm.S new file mode 100644 index 000000000..976ebd44b --- /dev/null +++ b/grub-core/lib/mips64/efi/loongson_asm.S @@ -0,0 +1,61 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. + */ + +#include <grub/symbol.h> + + .file "loongson.S" + .text + + .set push + .set noreorder + .align 4 + +VARIABLE (grub_efi_loongson_reset_start) + +VARIABLE (grub_efi_loongson_reset_system_addr) + .dword 0 + +reset_system: + bal 1f + move $a1, $zero +1: + ld $t9, -16($ra) + move $a2, $zero + jalr $t9 + move $a3, $zero + +FUNCTION(grub_efi_loongson_reset_cold) + b reset_system + li $a0, 0 + +FUNCTION(grub_efi_loongson_reset_warm) + b reset_system + li $a0, 1 + +FUNCTION(grub_efi_loongson_reset_shutdown) + b reset_system + li $a0, 2 + +FUNCTION(grub_efi_loongson_reset_suspend) + b reset_system + li $a0, 3 + +VARIABLE (grub_efi_loongson_reset_end) + + .set pop + diff --git a/grub-core/loader/mips64/linux.c b/grub-core/loader/mips64/linux.c index 84f9f2f81..3fc521d24 100644 --- a/grub-core/loader/mips64/linux.c +++ b/grub-core/loader/mips64/linux.c @@ -27,6 +27,7 @@ #include <grub/misc.h> #include <grub/command.h> #include <grub/cpu/relocator.h> +#include <grub/machine/loongson.h> #include <grub/memory.h> #include <grub/i18n.h> #include <grub/lib/cmdline.h> @@ -49,6 +50,54 @@ static grub_uint8_t *linux_args_addr; static grub_off_t rd_addr_arg_off, rd_size_arg_off; static int initrd_loaded = 0; +static inline grub_size_t +page_align (grub_size_t size) +{ + return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); +} + +/* Find the optimal number of pages for the memory map. Is it better to + move this code to efi/mm.c? */ +static grub_efi_uintn_t +find_mmap_size (void) +{ + static grub_efi_uintn_t mmap_size = 0; + + if (mmap_size != 0) + return mmap_size; + + mmap_size = (1 << 12); + while (1) + { + int ret; + grub_efi_memory_descriptor_t *mmap; + grub_efi_uintn_t desc_size; + + mmap = grub_malloc (mmap_size); + if (! mmap) + return 0; + + ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); + grub_free (mmap); + + if (ret < 0) + { + grub_error (GRUB_ERR_IO, "cannot get memory map"); + return 0; + } + else if (ret > 0) + break; + + mmap_size += (1 << 12); + } + + /* Increase the size a bit for safety, because GRUB allocates more on + later, and EFI itself may allocate more. */ + mmap_size += (1 << 12); + + return page_align (mmap_size); +} + static grub_err_t grub_linux_boot (void) { @@ -61,6 +110,28 @@ grub_linux_boot (void) state.gpr[4] = linux_argc; state.gpr[5] = (grub_addr_t) linux_args_addr; + if (grub_efi_is_loongson ()) + { + grub_efi_uintn_t mmap_size; + grub_efi_uintn_t desc_size; + grub_efi_memory_descriptor_t *mmap_buf; + grub_efi_loongson_boot_params *boot_params; + grub_err_t err; + + mmap_size = find_mmap_size (); + if (! mmap_size) + return grub_errno; + mmap_buf = grub_efi_allocate_pages (0, page_align (mmap_size) >> 12); + if (! mmap_buf) + return grub_error (GRUB_ERR_IO, "cannot allocate memory map"); + err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL, + &desc_size, NULL); + if (err) + return err; + + boot_params = grub_efi_loongson_get_boot_params (mmap_buf, mmap_size, desc_size); + state.gpr[6] = (grub_uint64_t) boot_params; + } state.jumpreg = 1; grub_relocator64_boot (relocator, state); @@ -249,7 +320,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), *linux_argv = 0; - grub_loader_set (grub_linux_boot, grub_linux_unload, GRUB_LOADER_FLAG_NORETURN); + grub_loader_set (grub_linux_boot, grub_linux_unload, + GRUB_LOADER_FLAG_NORETURN | + GRUB_LOADER_FLAG_LOONGSON_BOOT_PARAMS_NOFREE); initrd_loaded = 0; loaded = 1; grub_dl_ref (my_mod); diff --git a/include/grub/loader.h b/include/grub/loader.h index 7f82a499f..54c10dd95 100644 --- a/include/grub/loader.h +++ b/include/grub/loader.h @@ -33,6 +33,7 @@ enum { GRUB_LOADER_FLAG_NORETURN = 1, GRUB_LOADER_FLAG_PXE_NOT_UNLOAD = 2, + GRUB_LOADER_FLAG_LOONGSON_BOOT_PARAMS_NOFREE = 4, }; void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), diff --git a/include/grub/mips64/efi/loongson.h b/include/grub/mips64/efi/loongson.h new file mode 100644 index 000000000..5ac6958eb --- /dev/null +++ b/include/grub/mips64/efi/loongson.h @@ -0,0 +1,258 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_EFI_LOONGSON_HEADER +#define GRUB_EFI_LOONGSON_HEADER 1 + +#include <grub/types.h> + +#define GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID \ + { 0x4660f721, 0x2ec5, 0x416a, \ + { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ + } + +#define GRUB_EFI_LOONGSON_MMAP_MAX 128 + +typedef enum + { + GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW = 1, + GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH, + GRUB_EFI_LOONGSON_MEMORY_RESERVED, + GRUB_EFI_LOONGSON_PCI_IO, + GRUB_EFI_LOONGSON_PCI_MEM, + GRUB_EFI_LOONGSON_CFG_REG, + GRUB_EFI_LOONGSON_VIDEO_ROM, + GRUB_EFI_LOONGSON_ADAPTER_ROM, + GRUB_EFI_LOONGSON_ACPI_TABLE, + GRUB_EFI_LOONGSON_SMBIOS_TABLE, + GRUB_EFI_LOONGSON_UMA_VIDEO_RAM, + GRUB_EFI_LOONGSON_MAX_MEMORY_TYPE + } +grub_efi_loongson_memory_type; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint32_t nr_map; /* number of memory_maps */ + grub_uint32_t mem_freq; /* memory frequence */ + struct mem_map { + grub_uint32_t node_id; /* node_id which memory attached to */ + grub_uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ + grub_uint64_t mem_start; /* memory map start address */ + grub_uint32_t mem_size; /* each memory_map size, not the total size */ + } map[GRUB_EFI_LOONGSON_MMAP_MAX]; +} GRUB_PACKED +grub_efi_loongson_memory_map; + +/* + * Capability and feature descriptor structure for MIPS CPU + */ +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ + grub_uint32_t cputype; /* Loongson_3A/3B, etc. */ + grub_uint32_t total_node; /* num of total numa nodes */ + grub_uint16_t cpu_startup_core_id; /* Boot core id */ + grub_uint16_t reserved_cores_mask; + grub_uint32_t cpu_clock_freq; /* cpu_clock */ + grub_uint32_t nr_cpus; +} GRUB_PACKED +grub_efi_loongson_cpu_info; + +#define GRUB_EFI_LOONGSON_MAX_UARTS 64 + +typedef struct +{ + grub_uint32_t iotype; /* see include/linux/serial_core.h */ + grub_uint32_t uartclk; + grub_uint32_t int_offset; + grub_uint64_t uart_base; +} GRUB_PACKED +grub_efi_loongson_uart_device; + +#define GRUB_EFI_LOONGSON_MAX_SENSORS 64 + +typedef struct +{ + char name[32]; /* a formal name */ + char label[64]; /* a flexible description */ + grub_uint32_t type; /* SENSOR_* */ + grub_uint32_t id; /* instance id of a sensor-class */ + grub_uint32_t fan_policy; + grub_uint32_t fan_percent; /* only for constant speed policy */ + grub_uint64_t base_addr; /* base address of device registers */ +} GRUB_PACKED +grub_efi_loongson_sensor_device; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ + grub_uint32_t sing_double_channel; /* 1:single; 2:double */ + grub_uint32_t nr_uarts; + grub_efi_loongson_uart_device uarts[GRUB_EFI_LOONGSON_MAX_UARTS]; + grub_uint32_t nr_sensors; + grub_efi_loongson_sensor_device sensors[GRUB_EFI_LOONGSON_MAX_SENSORS]; + char has_ec; + char ec_name[32]; + grub_uint64_t ec_base_addr; + char has_tcm; + char tcm_name[32]; + grub_uint64_t tcm_base_addr; + grub_uint64_t workarounds; /* see workarounds.h */ +} GRUB_PACKED +grub_efi_loongson_system_info; + +typedef struct +{ + grub_uint16_t vers; + grub_uint16_t size; + grub_uint16_t rtr_bus; + grub_uint16_t rtr_devfn; + grub_uint32_t vendor; + grub_uint32_t device; + grub_uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ + grub_uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ + grub_uint64_t ht_enable; /* irqs used in this PIC */ + grub_uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ + grub_uint64_t pci_mem_start_addr; + grub_uint64_t pci_mem_end_addr; + grub_uint64_t pci_io_start_addr; + grub_uint64_t pci_io_end_addr; + grub_uint64_t pci_config_addr; + grub_uint32_t dma_mask_bits; +} GRUB_PACKED +grub_efi_loongson_irq_src_routing_table; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint16_t size; + grub_uint8_t flag; + char description[64]; +} GRUB_PACKED +grub_efi_loongson_interface_info; + +#define GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER 128 + +typedef struct +{ + grub_uint64_t start; /* resource start address */ + grub_uint64_t end; /* resource end address */ + char name[64]; + grub_uint32_t flags; +} +grub_efi_loongson_resource; + +/* arch specific additions */ +typedef struct +{ +} +grub_efi_loongson_archdev_data; + +typedef struct +{ + char name[64]; /* hold the device name */ + grub_uint32_t num_resources; /* number of device_resource */ + /* for each device's resource */ + grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; + /* arch specific additions */ + grub_efi_loongson_archdev_data archdata; +} +grub_efi_loongson_board_devices; + +typedef struct +{ + grub_uint16_t vers; /* version */ + char special_name[64]; /* special_atribute_name */ + grub_uint32_t loongson_special_type; /* type of special device */ + /* for each device's resource */ + grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; +} +grub_efi_loongson_special_attribute; + +typedef struct +{ + grub_uint64_t memory_offset; /* efi_loongson_memory_map struct offset */ + grub_uint64_t cpu_offset; /* efi_loongson_cpuinfo struct offset */ + grub_uint64_t system_offset; /* efi_loongson_system_info struct offset */ + grub_uint64_t irq_offset; /* efi_loongson_irq_src_routing_table struct offset */ + grub_uint64_t interface_offset; /* interface_info struct offset */ + grub_uint64_t special_offset; /* efi_loongson_special_attribute struct offset */ + grub_uint64_t boarddev_table_offset; /* efi_loongson_board_devices offset */ +} +grub_efi_loongson_params; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint64_t vga_bios; /* vga_bios address */ + grub_efi_loongson_params lp; +} +grub_efi_loongson_smbios_table; + +typedef struct +{ + grub_uint64_t reset_cold; + grub_uint64_t reset_warm; + grub_uint64_t reset_type; + grub_uint64_t shutdown; + grub_uint64_t do_suspend; /* NULL if not support */ +} +grub_efi_loongson_reset_system; + +typedef struct +{ + grub_uint64_t mps; /* MPS table */ + grub_uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ + grub_uint64_t acpi20; /* ACPI table (ACPI 2.0) */ + grub_efi_loongson_smbios_table smbios; /* SM BIOS table */ + grub_uint64_t sal_systab; /* SAL system table */ + grub_uint64_t boot_info; /* boot info table */ +} +grub_efi_loongson; + +typedef struct +{ + grub_efi_loongson efi; + grub_efi_loongson_reset_system reset_system; +} +grub_efi_loongson_boot_params; + +extern grub_uint64_t grub_efi_loongson_reset_system_addr; + +extern void grub_efi_loongson_reset_cold (void); +extern void grub_efi_loongson_reset_warm (void); +extern void grub_efi_loongson_reset_shutdown (void); +extern void grub_efi_loongson_reset_suspend (void); + +void grub_efi_loongson_init (void); +void grub_efi_loongson_fini (int flags); +void grub_efi_loongson_alloc_boot_params (void); +void grub_efi_loongson_free_boot_params (void); +grub_efi_loongson_smbios_table * grub_efi_loongson_get_smbios_table (void); + +int EXPORT_FUNC(grub_efi_is_loongson) (void); + +grub_efi_loongson_boot_params * +EXPORT_FUNC(grub_efi_loongson_get_boot_params) (grub_efi_memory_descriptor_t *mmap_buf, + grub_efi_uintn_t mmap_size, + grub_efi_uintn_t desc_size); + +#endif /* ! GRUB_EFI_LOONGSON_HEADER */ -- 2.11.1 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel