From 30aecb4a91047bc67607a4736d317a98f5adffd7 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Sat, 29 Mar 2014 23:59:50 +0000 Subject: Update the loongson codebase to recognize the so-called `EFI-like' interface supposedly provided by newer PMON firmware (on Loongson 2Gq and Loongson 3A systems). --- sys/arch/loongson/include/autoconf.h | 3 +- sys/arch/loongson/include/pmon.h | 161 ++++++++++++++++++- sys/arch/loongson/loongson/machdep.c | 302 ++++++++++++++++++++++------------- sys/arch/loongson/loongson/pmon.c | 185 ++++++++++++++++++++- 4 files changed, 530 insertions(+), 121 deletions(-) (limited to 'sys/arch/loongson') 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; /* @@ -351,61 +386,82 @@ 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); goto unsupported; } + /* + * 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); +} -- cgit v1.2.3