grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 4/4] mips64: Add support for Loongson.


From: wangr
Subject: [PATCH 4/4] mips64: Add support for Loongson.
Date: Tue, 7 Feb 2017 23:52:08 +0800

From: Heiher <address@hidden>

---
 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






reply via email to

[Prev in Thread] Current Thread [Next in Thread]