summaryrefslogtreecommitdiff
path: root/sys/arch/loongson
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/loongson')
-rw-r--r--sys/arch/loongson/include/autoconf.h3
-rw-r--r--sys/arch/loongson/include/pmon.h161
-rw-r--r--sys/arch/loongson/loongson/machdep.c302
-rw-r--r--sys/arch/loongson/loongson/pmon.c185
4 files changed, 530 insertions, 121 deletions
diff --git a/sys/arch/loongson/include/autoconf.h b/sys/arch/loongson/include/autoconf.h
index 200b47fc672..107ccd3f80a 100644
--- a/sys/arch/loongson/include/autoconf.h
+++ b/sys/arch/loongson/include/autoconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.h,v 1.10 2014/03/27 22:16:03 miod Exp $ */
+/* $OpenBSD: autoconf.h,v 1.11 2014/03/29 23:59:49 miod Exp $ */
/*
* Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -57,6 +57,7 @@ struct platform {
#define LOONGSON_FULOONG 0x0003 /* Lemote Fuloong */
#define LOONGSON_LYNLOONG 0x0004 /* Lemote Lynloong */
#define LOONGSON_EBT700 0x0005 /* eBenton EBT700 */
+#define LOONGSON_3A 0x0066 /* Loongson 2Gq or 3A based system */
char *vendor;
char *product;
diff --git a/sys/arch/loongson/include/pmon.h b/sys/arch/loongson/include/pmon.h
index ae110446374..f556c10821e 100644
--- a/sys/arch/loongson/include/pmon.h
+++ b/sys/arch/loongson/include/pmon.h
@@ -1,7 +1,7 @@
-/* $OpenBSD: pmon.h,v 1.2 2010/02/14 22:39:33 miod Exp $ */
+/* $OpenBSD: pmon.h,v 1.3 2014/03/29 23:59:49 miod Exp $ */
/*
- * Copyright (c) 2009 Miodrag Vallat.
+ * Copyright (c) 2009, 2012 Miodrag Vallat.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -44,8 +44,163 @@ char * pmon_gets(char *);
extern int32_t pmon_callvec;
const char *pmon_getarg(const int);
+void pmon_init(int32_t, int32_t, int32_t, int32_t, uint32_t);
+
+#define PMON_ENVTYPE_ENVP 0
+#define PMON_ENVTYPE_EFI 1
+int pmon_getenvtype(void);
+
+/*
+ * The new environment interface is a /salmigondis/ of badly thought-out
+ * structs put together, pretending to be inspired by EFI but conveniently
+ * omitting key EFI structs because they are deemed non-applicable to
+ * MIPS systems.
+ * Of course, some fields are absolute addresses, while others are relative
+ * pointers, to add to the confusion.
+ */
+
+struct pmon_env_reset {
+ void (*cold_boot)(void); /* not filled */
+ void (*warm_boot)(void);
+ void (*boot)(unsigned int); /* not filled */
+ void (*poweroff)(void);
+};
+
+/* all values are offsets relative to the beginning of the struct */
+struct pmon_env_ptr {
+ uint64_t offs_mem;
+ uint64_t offs_cpu;
+ uint64_t offs_sys;
+ uint64_t offs_irq;
+ uint64_t offs_iface;
+ uint64_t offs_special;
+ uint64_t offs_device;
+};
+
+struct pmon_env_smbios {
+ uint16_t version;
+ uint64_t vga_bios;
+ struct pmon_env_ptr ptrs;
+};
+
+struct pmon_env_efi {
+ uint64_t mps; /* not filled */
+ uint64_t acpi; /* not filled */
+ uint64_t acpi20; /* not filled */
+ struct pmon_env_smbios bios;
+ uint64_t sal_systab; /* not filled */
+ uint64_t bootinfo; /* not filled */
+};
+
+struct pmon_env {
+ struct pmon_env_efi efi;
+ struct pmon_env_reset reset;
+};
+
+#define PMON_MEM_MAX 128
+struct pmon_env_mem_entry {
+ uint32_t node;
+ uint32_t type;
+#define PMON_MEM_SYSTEM_LOW 1 /* physical memory <= 256 MB */
+#define PMON_MEM_SYSTEM_HIGH 2 /* physical memory > 256 MB */
+#define PMON_MEM_RESERVED 3
+#define PMON_MEM_PCI_IO 4
+#define PMON_MEM_PCI_MEM 5
+#define PMON_MEM_CPU_REGISTERS 6
+#define PMON_MEM_VIDEO_ROM 7
+#define PMON_MEM_OTHER_ROM 8
+#define PMON_MEM_ACPI_TABLE 9
+ uint64_t address;
+ uint32_t size;
+};
+struct pmon_env_mem {
+ uint16_t version; /* not filled */
+ uint32_t nentries;
+ uint32_t mem_freq;
+ struct pmon_env_mem_entry mem_map[PMON_MEM_MAX];
+} __packed;
+
+struct pmon_env_cpu {
+ uint16_t version; /* not filled */
+ uint32_t prid; /* cop0 PrID */
+ uint32_t cputype;
+/* 0 and 1 are supposedly intended for 2E and 2F, which do NOT provide this
+ interface; moreover Linux and PMON disagree on the values and have 2E and
+ 2F swapped. */
+#define PMON_CPUTYPE_LS3A 2
+#define PMON_CPUTYPE_LS3B 3
+#define PMON_CPUTYPE_LS1A 4
+#define PMON_CPUTYPE_LS1B 5
+ uint32_t node; /* total number of NUMA nodes */
+ uint32_t coreid; /* boot CPU core id */
+ uint32_t speed;
+ uint32_t ncpus;
+} __packed;
+
+struct pmon_env_sys {
+ uint16_t version; /* not filled */
+ uint32_t ccnuma_smp;
+ uint32_t double_channel;
+} __packed;
+
+struct pmon_env_irq {
+ uint16_t version; /* not filled */
+ uint16_t size; /* not filled */
+ uint16_t rtr_bus; /* not filled */
+ uint16_t rtr_devfn; /* not filled */
+ uint32_t vendor; /* not filled */
+ uint32_t device; /* not filled */
+ uint32_t pic_type;
+#define PMON_IRQ_PIC_HT 0
+#define PMON_IRQ_PIC_I8259 1
+ uint64_t ht_interrupt_bit;
+ uint64_t ht_enable;
+ uint32_t node;
+ uint64_t pci_memory_space_start;
+ uint64_t pci_memory_space_end;
+ uint64_t pci_io_space_start; /* not filled */
+ uint64_t pci_io_space_end; /* not filled */
+ uint64_t pci_cfg_space; /* not filled */
+} __packed;
+
+struct pmon_env_iface {
+ uint16_t version;
+#define PMON_IFACE_VERSION 0x0001
+ uint16_t size;
+ uint8_t flag;
+ char description[64]; /* firmware version */
+} __packed;
+
+#define PMON_RESOURCE_MAX 128
+struct pmon_env_resource {
+ uint64_t start;
+ uint64_t end;
+ char name[64];
+ uint32_t flags;
+};
+struct pmon_env_special {
+ uint16_t version;
+ char name[64];
+ uint32_t type;
+ struct pmon_env_resource resource[PMON_RESOURCE_MAX];
+};
+
+struct pmon_env_device {
+ char name[64]; /* system description */
+ uint32_t nentries;
+ struct pmon_env_resource resource[PMON_RESOURCE_MAX];
+};
+
const char *pmon_getenv(const char *);
-void pmon_init(int32_t, int32_t, int32_t, int32_t);
+
+const struct pmon_env_reset *pmon_get_env_reset(void);
+const struct pmon_env_mem *pmon_get_env_mem(void);
+const struct pmon_env_cpu *pmon_get_env_cpu(void);
+const struct pmon_env_sys *pmon_get_env_sys(void);
+const struct pmon_env_irq *pmon_get_env_irq(void);
+const struct pmon_env_iface *pmon_get_env_iface(void);
+const struct pmon_env_special *pmon_get_env_special(void);
+const struct pmon_env_device *pmon_get_env_device(void);
#endif /* _KERNEL || _STANDALONE */
diff --git a/sys/arch/loongson/loongson/machdep.c b/sys/arch/loongson/loongson/machdep.c
index c57f650e5da..29aa8a462a3 100644
--- a/sys/arch/loongson/loongson/machdep.c
+++ b/sys/arch/loongson/loongson/machdep.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: machdep.c,v 1.45 2014/03/27 22:16:03 miod Exp $ */
+/* $OpenBSD: machdep.c,v 1.46 2014/03/29 23:59:49 miod Exp $ */
/*
- * Copyright (c) 2009, 2010 Miodrag Vallat.
+ * Copyright (c) 2009, 2010, 2014 Miodrag Vallat.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -93,9 +93,10 @@ char cpu_model[30];
char pmon_bootp[80];
/*
- * Even though the system is 64bit, the hardware is constrained to up
- * to 2G of contigous physical memory (direct 2GB DMA area), so there
- * is no particular constraint. paddr_t is long so:
+ * Even though the system is 64bit, 2E- and 2F-based hardware is constrained
+ * to up to 2G of contigous physical memory (direct 2GB DMA area). 2Gq- and
+ * 3A-based hardware only supports 32-bit DMA addresses, even though
+ * physical memory may exist beyond 4GB.
*/
struct uvm_constraint_range dma_constraint = { 0x0, 0xffffffffUL };
struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
@@ -137,11 +138,12 @@ static void dobootopts(int);
void dumpsys(void);
void dumpconf(void);
extern void parsepmonbp(void);
-const struct platform *loongson_identify(const char *);
-vaddr_t mips_init(int32_t, int32_t, int32_t, int32_t, char *);
+const struct platform *loongson_identify(const char *, int);
+vaddr_t mips_init(uint64_t, uint64_t, uint64_t, uint64_t, char *);
extern void loongson2e_setup(u_long, u_long);
extern void loongson2f_setup(u_long, u_long);
+extern void loongson3a_setup(u_long, u_long);
cons_decl(pmon);
@@ -170,10 +172,12 @@ extern const struct platform ebenton_platform;
extern const struct platform fuloong_platform;
extern const struct platform gdium_platform;
extern const struct platform generic2e_platform;
+extern const struct platform lemote3a_platform;
extern const struct platform lynloong_platform;
extern const struct platform yeeloong_platform;
const struct bonito_flavour bonito_flavours[] = {
+#ifdef CPU_LOONGSON2
/* eBenton EBT700 netbook */
{ "EBT700", &ebenton_platform }, /* prefix added by user */
/* Lemote Fuloong 2F mini-PC */
@@ -190,6 +194,16 @@ const struct bonito_flavour bonito_flavours[] = {
{ "LM8101", &yeeloong_platform },
/* Lemote Lynloong all-in-one computer */
{ "LM9001", &lynloong_platform },
+#endif
+#ifdef CPU_LOONGSON3
+ /* Laptops */
+ { "A1004", &lemote3a_platform }, /* 3A */
+ { "A1201", &lemote3a_platform }, /* 2Gq */
+ /* Lemote Xinghuo 6100 (mini-ITX PC) */
+ { "A1101", &lemote3a_platform }, /* 3A */
+ /* All-in-one PC */
+ { "A1205", &lemote3a_platform }, /* 2Gq */
+#endif
{ NULL }
};
@@ -198,82 +212,101 @@ const struct bonito_flavour bonito_flavours[] = {
* scarce PMON version information and whatever else we can figure.
*/
const struct platform *
-loongson_identify(const char *version)
+loongson_identify(const char *version, int envtype)
{
const struct bonito_flavour *f;
- if (version == NULL) {
- /*
- * If there is no `Version' variable, we expect to be running
- * on a 2E system, use the generic code and hope for the best.
- */
- if (loongson_ver == 0x2e) {
- return &generic2e_platform;
- } else {
- pmon_printf("Unable to figure out model!\n");
- return NULL;
- }
- }
-
- for (f = bonito_flavours; f->prefix != NULL; f++)
- if (strncmp(version, f->prefix, strlen(f->prefix)) == 0)
- return f->platform;
+ switch (envtype) {
+ case PMON_ENVTYPE_EFI:
+ return NULL;
+ break;
- /*
- * Early Lemote designs shipped without a model prefix.
- *
- * We can reasonably expect these to be close enough to either the
- * first generation Fuloong 2F design (LM6002), or the 7 inch
- * first netbook model; we can tell them apart by looking at which
- * video chip they embed.
- *
- * Note that this is only worth doing if the version string is
- * 1.2.something (1.3 onwards are expected to have a model prefix,
- * and there are currently no reports of 1.1 and
- * below being 2F systems).
- *
- * LM6002 users are encouraged to add the system model prefix to
- * the `Version' variable.
- */
- if (strncmp(version, "1.2.", 4) == 0) {
- const struct platform *p = NULL;
- pcitag_t tag;
- pcireg_t id, class;
- int dev;
-
- pmon_printf("No model prefix in version string \"%s\".\n",
- version);
-
- for (dev = 0; dev < 32; dev++) {
- tag = pci_make_tag_early(0, dev, 0);
- id = pci_conf_read_early(tag, PCI_ID_REG);
- if (id == 0 || PCI_VENDOR(id) == PCI_VENDOR_INVALID)
- continue;
-
- /* no need to check for DEVICE_IS_VGA_PCI here
- since we expect a linear framebuffer */
- class = pci_conf_read_early(tag, PCI_CLASS_REG);
- if (PCI_CLASS(class) != PCI_CLASS_DISPLAY ||
- (PCI_SUBCLASS(class) != PCI_SUBCLASS_DISPLAY_VGA &&
- PCI_SUBCLASS(class) != PCI_SUBCLASS_DISPLAY_MISC))
- continue;
-
- switch (id) {
- case PCI_ID_CODE(PCI_VENDOR_SIS,
- PCI_PRODUCT_SIS_315PRO_VGA):
- p = &fuloong_platform;
- break;
- case PCI_ID_CODE(PCI_VENDOR_SMI,
- PCI_PRODUCT_SMI_SM712):
- p = &ebenton_platform;
- break;
+ default:
+ case PMON_ENVTYPE_ENVP:
+ if (version == NULL) {
+ /*
+ * If there is no `Version' variable, we expect to be
+ * running on a 2E system, use the generic code and
+ * hope for the best.
+ */
+ if (loongson_ver == 0x2e) {
+ return &generic2e_platform;
+ } else {
+ pmon_printf("Unable to figure out model!\n");
+ return NULL;
}
+ }
- if (p != NULL) {
- pmon_printf("Attempting to match as %s %s\n",
- p->vendor, p->product);
- return p;
- }
+ for (f = bonito_flavours; f->prefix != NULL; f++)
+ if (strncmp(version, f->prefix, strlen(f->prefix)) == 0)
+ return f->platform;
+
+ /*
+ * Early Lemote designs shipped without a model prefix.
+ *
+ * We can reasonably expect these to be close enough to either
+ * the first generation Fuloong 2F design (LM6002), or the 7
+ * inch first netbook model; we can tell them apart by looking
+ * at which video chip they embed.
+ *
+ * Note that this is only worth doing if the version string is
+ * 1.2.something (1.3 onwards are expected to have a model
+ * prefix, and there are currently no reports of 1.1 and
+ * below being 2F systems).
+ *
+ * LM6002 users are encouraged to add the system model prefix to
+ * the `Version' variable.
+ */
+ if (strncmp(version, "1.2.", 4) == 0) {
+ const struct platform *p = NULL;
+ pcitag_t tag;
+ pcireg_t id, class;
+ int dev;
+
+ pmon_printf("No model prefix "
+ "in version string \"%s\".\n", version);
+
+ if (loongson_ver == 0x2f)
+ for (dev = 0; dev < 32; dev++) {
+ tag = pci_make_tag_early(0, dev, 0);
+ id = pci_conf_read_early(tag,
+ PCI_ID_REG);
+ if (id == 0 || PCI_VENDOR(id) ==
+ PCI_VENDOR_INVALID)
+ continue;
+
+ /*
+ * No need to check for
+ * DEVICE_IS_VGA_PCI here, since we
+ * expect a linear framebuffer.
+ */
+ class = pci_conf_read_early(tag,
+ PCI_CLASS_REG);
+ if (PCI_CLASS(class) !=
+ PCI_CLASS_DISPLAY ||
+ (PCI_SUBCLASS(class) !=
+ PCI_SUBCLASS_DISPLAY_VGA &&
+ PCI_SUBCLASS(class) !=
+ PCI_SUBCLASS_DISPLAY_MISC))
+ continue;
+
+ switch (id) {
+ case PCI_ID_CODE(PCI_VENDOR_SIS,
+ PCI_PRODUCT_SIS_315PRO_VGA):
+ p = &fuloong_platform;
+ break;
+ case PCI_ID_CODE(PCI_VENDOR_SMI,
+ PCI_PRODUCT_SMI_SM712):
+ p = &ebenton_platform;
+ break;
+ }
+ }
+
+ if (p != NULL) {
+ pmon_printf("Attempting to match as "
+ "%s %s\n", p->vendor, p->product);
+ return p;
+ }
}
}
@@ -288,10 +321,10 @@ loongson_identify(const char *version)
*/
vaddr_t
-mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv,
+mips_init(uint64_t argc, uint64_t argv, uint64_t envp, uint64_t cv,
char *boot_esym)
{
- uint prid;
+ uint32_t prid;
u_long memlo, memhi, cpuspeed;
vaddr_t xtlb_handler;
const char *envvar;
@@ -320,7 +353,9 @@ mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv,
* Set up early console output.
*/
- pmon_init(argc, argv, envp, cv);
+ prid = cp0_get_prid();
+ pmon_init((int32_t)argc, (int32_t)argv, (int32_t)envp, (int32_t)cv,
+ prid);
cn_tab = &pmoncons;
/*
@@ -352,48 +387,38 @@ mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv,
}
/*
- * Try and figure out what kind of hardware we are.
- */
-
- envvar = pmon_getenv("systype");
- if (envvar == NULL) {
- pmon_printf("Unable to figure out system type!\n");
- goto unsupported;
- }
- if (strcmp(envvar, "Bonito") != 0) {
- pmon_printf("This kernel doesn't support system type \"%s\".\n",
- envvar);
- goto unsupported;
- }
-
- /*
* While the kernel supports other processor types than Loongson,
- * we are not expecting a Bonito-based system with a different
- * processor. Just to be on the safe side, refuse to run on
- * non Loongson2 processors for now.
+ * we are currently not expecting to run on a system with a
+ * different processor. Just to be on the safe side, refuse to
+ * run on non-Loongson2 processors for now.
*/
- prid = cp0_get_prid();
switch ((prid >> 8) & 0xff) {
case MIPS_LOONGSON2:
switch (prid & 0xff) {
+#ifdef CPU_LOONGSON2
+#ifdef CPU_LOONGSON2C
case 0x00:
loongson_ver = 0x2c;
break;
+#endif
case 0x02:
loongson_ver = 0x2e;
break;
case 0x03:
loongson_ver = 0x2f;
break;
+#endif
+#ifdef CPU_LOONGSON3
case 0x05:
loongson_ver = 0x3a;
break;
- }
- if (loongson_ver == 0x2e || loongson_ver == 0x2f)
+#endif
+ default:
break;
- /* FALLTHROUGH */
- default:
+ }
+ }
+ if (loongson_ver == 0) {
pmon_printf("This kernel doesn't support processor type 0x%x"
", version %d.%d.\n",
(prid >> 8) & 0xff, (prid >> 4) & 0x0f, prid & 0x0f);
@@ -401,11 +426,42 @@ mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv,
}
/*
+ * Try and figure out what kind of hardware we are.
+ */
+
+ switch (pmon_getenvtype()) {
+ default:
+ pmon_printf("Unable to figure out "
+ "firmware environment information!\n");
+ goto unsupported;
+
+ case PMON_ENVTYPE_EFI:
+ /*
+ * We can reasonably expect to be running on a beast we can
+ * tame, here.
+ */
+ break;
+
+ case PMON_ENVTYPE_ENVP:
+ envvar = pmon_getenv("systype");
+ if (envvar == NULL) {
+ pmon_printf("Unable to figure out system type!\n");
+ goto unsupported;
+ }
+ if (strcmp(envvar, "Bonito") != 0) {
+ pmon_printf("This kernel doesn't support system type \"%s\".\n",
+ envvar);
+ goto unsupported;
+ }
+ }
+
+ /*
* Try to figure out what particular machine we run on, depending
* on the PMON version information.
*/
- if ((sys_platform = loongson_identify(pmon_getenv("Version"))) == NULL)
+ if ((sys_platform = loongson_identify(pmon_getenv("Version"),
+ pmon_getenvtype())) == NULL)
goto unsupported;
hw_vendor = sys_platform->vendor;
@@ -471,14 +527,20 @@ mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv,
memhi = 0;
switch (loongson_ver) {
+ default:
+#ifdef CPU_LOONGSON2
case 0x2e:
loongson2e_setup(memlo, memhi);
break;
- default:
case 0x2f:
- case 0x3a:
loongson2f_setup(memlo, memhi);
break;
+#endif
+#ifdef CPU_LOONGSON3
+ case 0x3a:
+ loongson3a_setup(memlo, memhi);
+ break;
+#endif
}
if (sys_platform->setup != NULL)
@@ -543,14 +605,33 @@ mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv,
bootcpu_hwinfo.type = (prid >> 8) & 0xff;
/* FPU reports itself as type 5, version 0.1... */
bootcpu_hwinfo.c1prid = bootcpu_hwinfo.c0prid;
- bootcpu_hwinfo.tlbsize = 64;
/*
- * Configure cache.
+ * Configure cache and tlb.
*/
- Loongson2_ConfigCache(curcpu());
- Loongson2_SyncCache(curcpu());
+ switch (loongson_ver) {
+ default:
+#ifdef CPU_LOONGSON2
+#ifdef CPU_LOONGSON2C
+ case 0x2c:
+#endif
+ case 0x2e:
+ case 0x2f:
+ bootcpu_hwinfo.tlbsize = 64;
+ Loongson2_ConfigCache(curcpu());
+ Loongson2_SyncCache(curcpu());
+ break;
+#endif
+#ifdef CPU_LOONGSON3
+ case 0x3a:
+ bootcpu_hwinfo.tlbsize =
+ 1 + ((cp0_get_config_1() >> 25) & 0x3f);
+ Loongson3_ConfigCache(curcpu());
+ Loongson3_SyncCache(curcpu());
+ break;
+#endif
+ }
tlb_init(bootcpu_hwinfo.tlbsize);
@@ -739,6 +820,7 @@ consinit()
static int console_ok = 0;
if (console_ok == 0) {
+ cn_tab = NULL;
cninit();
console_ok = 1;
}
diff --git a/sys/arch/loongson/loongson/pmon.c b/sys/arch/loongson/loongson/pmon.c
index 94b3fb92b01..306a3ba879f 100644
--- a/sys/arch/loongson/loongson/pmon.c
+++ b/sys/arch/loongson/loongson/pmon.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: pmon.c,v 1.4 2010/02/16 21:29:54 miod Exp $ */
+/* $OpenBSD: pmon.c,v 1.5 2014/03/29 23:59:49 miod Exp $ */
/*
- * Copyright (c) 2009 Miodrag Vallat.
+ * Copyright (c) 2009, 2012 Miodrag Vallat.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -26,9 +26,12 @@
int pmon_argc;
int32_t *pmon_argv;
int32_t *pmon_envp;
+vaddr_t pmon_envbase;
+int pmon_envtype;
void
-pmon_init(int32_t argc, int32_t argv, int32_t envp, int32_t callvec)
+pmon_init(int32_t argc, int32_t argv, int32_t envp, int32_t callvec,
+ uint32_t prid)
{
pmon_callvec = callvec;
@@ -36,6 +39,75 @@ pmon_init(int32_t argc, int32_t argv, int32_t envp, int32_t callvec)
/* sign extend pointers */
pmon_argv = (int32_t *)(vaddr_t)argv;
pmon_envp = (int32_t *)(vaddr_t)envp;
+
+ /*
+ * Those ``smart'' brains at Lemote have decided to change the way
+ * system information is passed from PMON to the kernel: earlier
+ * PMON versions pass the usual environment array, while newer
+ * versions pass a struct, without any form of magic number in it
+ * (beginner's mistake #1).
+ *
+ * Of course, to make things worse, quoting
+ * http://www.linux-mips.org/archives/linux-mips/2012-08/msg00233.html :
+ * ``All Loongson-based machines support this new interface except
+ * 2E/2F series.''
+ *
+ * This is obviously not true, there are 3A systems which pass the
+ * good old environment variables around... I have such a system here.
+ */
+
+ switch (prid & 0xff) {
+ case 0x02: /* 2E */
+ case 0x03: /* 2F */
+ pmon_envtype = PMON_ENVTYPE_ENVP;
+ pmon_envbase = CKSEG1_BASE;
+ break;
+ default:
+ {
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+
+ /*
+ * `pmon_envp' either points to an EFI struct or to a
+ * NULL-terminated array of 32-bit pointers.
+ *
+ * Since the EFI struct starts with a few 64 bit pointers,
+ * it should be easy to figure out which flavour we are
+ * facing by checking the top 32 bits of these 64 bit
+ * pointers.
+ *
+ * However, not all of these pointers are actually initialized
+ * by the firmware (beginner's mistake #2). Therefore, we can
+ * only safely check the first two fields of the `smbios'
+ * struct:
+ * - the version number must be small
+ * - the `vga bios' pointer must be aligned to an 1MB boundary,
+ * and below 4GB.
+ *
+ * Of course, I can reasonably expect these assumptions to
+ * be broken in future systems. Where would be the fun if
+ * not?
+ */
+ if (env->efi.bios.version < 0x2000 &&
+ (env->efi.bios.vga_bios & 0xfffff) == 0 &&
+ (env->efi.bios.vga_bios >> 32) == 0) {
+ pmon_envtype = PMON_ENVTYPE_EFI;
+ } else {
+ pmon_envtype = PMON_ENVTYPE_ENVP;
+ pmon_envbase = CKSEG0_BASE;
+ }
+ }
+ break;
+ }
+
+ /*
+ * Figure out where the environment pointers are supposed to live.
+ * Loongson 2[EF] systems use uncached memory, while 2G onwards
+ * apparently use cached memory.
+ */
+ if (pmon_envtype == PMON_ENVTYPE_ENVP) {
+ pmon_envbase = (uint64_t)*pmon_envp < CKSEG1_BASE ?
+ CKSEG0_BASE : CKSEG1_BASE;
+ }
}
const char *
@@ -47,6 +119,12 @@ pmon_getarg(const int argno)
return (const char *)(vaddr_t)pmon_argv[argno];
}
+int
+pmon_getenvtype()
+{
+ return pmon_envtype;
+}
+
const char *
pmon_getenv(const char *var)
{
@@ -54,7 +132,7 @@ pmon_getenv(const char *var)
const char *envstr;
size_t varlen;
- if (envptr == NULL)
+ if (envptr == NULL || pmon_envtype != PMON_ENVTYPE_ENVP)
return NULL;
varlen = strlen(var);
@@ -74,10 +152,9 @@ pmon_getenv(const char *var)
* tell the user (in case this prevents us from finding
* important information).
*/
- if ((vaddr_t)envstr < CKSEG1_BASE ||
- (vaddr_t)envstr >= CKSSEG_BASE) {
+ if ((vaddr_t)envstr - pmon_envbase >= CKSEG_SIZE) {
printf("WARNING! CORRUPTED ENVIRONMENT!\n");
- printf("Unable to search for %s.\n", var);
+ printf("Unable to search for \"%s\".\n", var);
#ifdef _STANDALONE
printf("If boot fails, power-cycle the machine.\n");
#else
@@ -97,3 +174,97 @@ pmon_getenv(const char *var)
return NULL;
}
+
+const struct pmon_env_reset *pmon_get_env_reset()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return &env->reset;
+}
+
+const struct pmon_env_mem *pmon_get_env_mem()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+ uint64_t va = (uint64_t)&env->efi.bios.ptrs;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return (const struct pmon_env_mem *)
+ (va + env->efi.bios.ptrs.offs_mem);
+}
+
+const struct pmon_env_cpu *pmon_get_env_cpu()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+ uint64_t va = (uint64_t)&env->efi.bios.ptrs;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return (const struct pmon_env_cpu *)
+ (va + env->efi.bios.ptrs.offs_cpu);
+}
+
+const struct pmon_env_sys *pmon_get_env_sys()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+ uint64_t va = (uint64_t)&env->efi.bios.ptrs;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return (const struct pmon_env_sys *)
+ (va + env->efi.bios.ptrs.offs_sys);
+}
+
+const struct pmon_env_irq *pmon_get_env_irq()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+ uint64_t va = (uint64_t)&env->efi.bios.ptrs;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return (const struct pmon_env_irq *)
+ (va + env->efi.bios.ptrs.offs_irq);
+}
+
+const struct pmon_env_iface *pmon_get_env_iface()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+ uint64_t va = (uint64_t)&env->efi.bios.ptrs;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return (const struct pmon_env_iface *)
+ (va + env->efi.bios.ptrs.offs_iface);
+}
+
+const struct pmon_env_special *pmon_get_env_special()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+ uint64_t va = (uint64_t)&env->efi.bios.ptrs;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return (const struct pmon_env_special *)
+ (va + env->efi.bios.ptrs.offs_special);
+}
+
+const struct pmon_env_device *pmon_get_env_device()
+{
+ struct pmon_env *env = (struct pmon_env *)pmon_envp;
+ uint64_t va = (uint64_t)&env->efi.bios.ptrs;
+
+ if (pmon_envtype != PMON_ENVTYPE_EFI)
+ return NULL;
+
+ return (const struct pmon_env_device *)
+ (va + env->efi.bios.ptrs.offs_device);
+}