/* $OpenBSD: arcbios.c,v 1.9 2007/04/26 17:02:40 miod Exp $ */ /*- * Copyright (c) 1996 M. Warner Losh. All rights reserved. * Copyright (c) 1996-2004 Opsycon AB. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #if defined(TGT_ORIGIN200) || defined(TGT_ORIGIN2000) #include #endif int bios_is_32bit = 1; /* * If we can not get the onboard ethernet address to override this bogus * value, ether_ifattach() will pick a valid address. */ char bios_enaddr[20] = "ff:ff:ff:ff:ff:ff"; extern int physmem; /* Total physical memory size */ extern int rsvdmem; /* Total reserved memory size */ void bios_configure_memory(void); int bios_get_system_type(void); arc_dsp_stat_t displayinfo; /* Save area for display status info. */ static struct systypes { char *sys_vend; /* Vendor ID if name is ambigous */ char *sys_name; /* May be left NULL if name is sufficient */ int sys_type; } sys_types[] = { { NULL, "PICA-61", ACER_PICA_61 }, { NULL, "NEC-R94", ACER_PICA_61 }, { NULL, "DESKTECH-TYNE", DESKSTATION_TYNE }, { NULL, "DESKTECH-ARCStation I", DESKSTATION_RPC44 }, { NULL, "Microsoft-Jazz", MAGNUM }, { NULL, "RM200PCI", SNI_RM200 }, { NULL, "SGI-IP17", SGI_CRIMSON }, { NULL, "SGI-IP19", SGI_ONYX }, { NULL, "SGI-IP20", SGI_INDIGO }, { NULL, "SGI-IP21", SGI_POWER }, { NULL, "SGI-IP22", SGI_INDY }, { NULL, "SGI-IP25", SGI_POWER10 }, { NULL, "SGI-IP26", SGI_POWERI }, { NULL, "SGI-IP27", SGI_O200 }, { NULL, "SGI-IP32", SGI_O2 }, }; #define KNOWNSYSTEMS (sizeof(sys_types) / sizeof(struct systypes)) /* * ARC Bios trampoline code. */ #define ARC_Call(Name,Offset) \ __asm__("\n" \ " .text\n" \ " .ent " #Name "\n" \ " .align 3\n" \ " .set noreorder\n" \ " .globl " #Name "\n" \ #Name":\n" \ " lw $2, bios_is_32bit\n"\ " beqz $2, 1f\n" \ " nop\n" \ " lw $2, 0xffffffff80001020\n"\ " lw $2," #Offset "($2)\n"\ " jr $2\n" \ " nop\n" \ "1:\n" \ " ld $2, 0xffffffff80001040\n"\ " ld $2, 2*" #Offset "($2)\n"\ " jr $2\n" \ " nop\n" \ " .end " #Name "\n" ); ARC_Call(Bios_Load, 0x00); ARC_Call(Bios_Invoke, 0x04); ARC_Call(Bios_Execute, 0x08); ARC_Call(Bios_Halt, 0x0c); ARC_Call(Bios_PowerDown, 0x10); ARC_Call(Bios_Restart, 0x14); ARC_Call(Bios_Reboot, 0x18); ARC_Call(Bios_EnterInteractiveMode, 0x1c); ARC_Call(Bios_Unused1, 0x20); ARC_Call(Bios_GetPeer, 0x24); ARC_Call(Bios_GetChild, 0x28); ARC_Call(Bios_GetParent, 0x2c); ARC_Call(Bios_GetConfigurationData, 0x30); ARC_Call(Bios_AddChild, 0x34); ARC_Call(Bios_DeleteComponent, 0x38); ARC_Call(Bios_GetComponent, 0x3c); ARC_Call(Bios_SaveConfiguration, 0x40); ARC_Call(Bios_GetSystemId, 0x44); ARC_Call(Bios_GetMemoryDescriptor, 0x48); ARC_Call(Bios_Unused2, 0x4c); ARC_Call(Bios_GetTime, 0x50); ARC_Call(Bios_GetRelativeTime, 0x54); ARC_Call(Bios_GetDirectoryEntry, 0x58); ARC_Call(Bios_Open, 0x5c); ARC_Call(Bios_Close, 0x60); ARC_Call(Bios_Read, 0x64); ARC_Call(Bios_GetReadStatus, 0x68); ARC_Call(Bios_Write, 0x6c); ARC_Call(Bios_Seek, 0x70); ARC_Call(Bios_Mount, 0x74); ARC_Call(Bios_GetEnvironmentVariable, 0x78); ARC_Call(Bios_SetEnvironmentVariable, 0x7c); ARC_Call(Bios_GetFileInformation, 0x80); ARC_Call(Bios_SetFileInformation, 0x84); ARC_Call(Bios_FlushAllCaches, 0x88); ARC_Call(Bios_TestUnicodeCharacter, 0x8c); ARC_Call(Bios_GetDisplayStatus, 0x90); /* * Simple getchar/putchar interface. */ int bios_getchar() { char buf[4]; int cnt; if (Bios_Read(0, &buf[0], 1, &cnt) != 0) return(-1); return(buf[0] & 255); } void bios_putchar(c) char c; { char buf[4]; int cnt; if (c == '\n') { buf[0] = '\r'; buf[1] = c; cnt = 2; if (displayinfo.CursorYPosition < displayinfo.CursorMaxYPosition) displayinfo.CursorYPosition++; } else { buf[0] = c; cnt = 1; } Bios_Write(1, &buf[0], cnt, &cnt); } void bios_putstring(s) char *s; { while (*s) { bios_putchar(*s++); } } void bios_printf(const char *fmt, ...) { va_list ap; char buf[1024]; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); bios_putstring(buf); } /* * Get memory descriptor for the memory configuration and * create a layout database used by pmap init to set up * the memory system. Note that kernel option "MACHINE_NONCONTIG" * must be set for systems with non contigous physical memory. * * Concatenate obvious adjecent segments. */ void bios_configure_memory() { arc_mem_t *descr = 0; struct phys_mem_desc *m; vaddr_t seg_start, seg_end; int i; descr = (arc_mem_t *)Bios_GetMemoryDescriptor(descr); while(descr != 0) { seg_start = descr->BasePage; seg_end = seg_start + descr->PageCount; switch (descr->Type) { case BadMemory: /* Have no use for theese */ break; case FreeMemory: case FreeContigous: physmem += descr->PageCount; m = 0; for (i = 0; i < MAXMEMSEGS; i++) { if (mem_layout[i].mem_last_page == 0) { if (m == 0) m = &mem_layout[i]; /* free */ } else if (seg_end == mem_layout[i].mem_first_page) { m = &mem_layout[i]; m->mem_first_page = seg_start; } else if (mem_layout[i].mem_last_page == seg_start) { m = &mem_layout[i]; m->mem_last_page = seg_end; } } if (m && m->mem_first_page == 0) { m->mem_first_page = seg_start; m->mem_last_page = seg_end; } break; case ExeceptionBlock: case SystemParameterBlock: case FirmwareTemporary: case FirmwarePermanent: rsvdmem += descr->PageCount; physmem += descr->PageCount; break; case LoadedProgram: /* Count this into total memory */ physmem += descr->PageCount; break; default: /* Unknown type, leave it alone... */ break; } descr = (arc_mem_t *)Bios_GetMemoryDescriptor(descr); } #ifdef DEBUG_MEM_LAYOUT for ( i = 0; i < MAXMEMSEGS; i++) { if (mem_layout[i].mem_first_page) { bios_printf("MEM %d, 0x%x to 0x%x\n",i, mem_layout[i].mem_first_page * 4096, mem_layout[i].mem_last_page * 4096); } } #endif } /* * Find out system type. */ int bios_get_system_type() { arc_config_t *cf; arc_sid_t *sid; int i; /* * Figure out if this is an ARC Bios machine and if its 32 or 64 bits. */ if ((ArcBiosBase32->magic == ARC_PARAM_BLK_MAGIC) || (ArcBiosBase32->magic == ARC_PARAM_BLK_MAGIC_BUG)) { bios_is_32bit = 1; bios_printf("ARCS32 Firmware Version %d.%d\n", ArcBiosBase32->version, ArcBiosBase32->revision); } else if ((ArcBiosBase64->magic == ARC_PARAM_BLK_MAGIC) || (ArcBiosBase64->magic == ARC_PARAM_BLK_MAGIC_BUG)) { bios_is_32bit = 0; bios_printf("ARCS64 Firmware Version %d.%d\n", ArcBiosBase64->version, ArcBiosBase64->revision); } else { return -1; /* XXX BAD BAD BAD!!! */ } sid = (arc_sid_t *)Bios_GetSystemId(); cf = (arc_config_t *)Bios_GetChild(NULL); if (cf) { for (i = 0; i < KNOWNSYSTEMS; i++) { if (strcmp(sys_types[i].sys_name, (char *)(long)cf->id) != 0) continue; if (sys_types[i].sys_vend && strncmp(sys_types[i].sys_vend, sid->vendor, 8) != 0) continue; return (sys_types[i].sys_type); /* Found it. */ } #if defined(TGT_ORIGIN200) || defined(TGT_ORIGIN2000) } else if (IP27_KLD_KLCONFIG(0)->magic == IP27_KLDIR_MAGIC) { /* If we find a kldir assume IP27 */ return SGI_O200; #endif } sid->vendor[8] = 0; sid->prodid[8] = 0; bios_printf("UNRECOGNIZED SYSTEM '%s' VENDOR '%s' PRODUCT '%s'\n", cf ? (char *)(long)cf->id : "??", sid->vendor, sid->prodid); bios_printf("See the www.openbsd.org for further information.\n"); bios_printf("Halting system!\n"); Bios_Halt(); bios_printf("Halting failed, use manual reset!\n"); while(1); } /* * Incomplete version of bios_ident */ void bios_ident() { sys_config.system_type = bios_get_system_type(); if (sys_config.system_type < 0 || sys_config.system_type == SGI_O200) { return; } /* If not an IP27 platform, get memory configuration from bios */ bios_configure_memory(); #ifdef __arc__ displayinfo = *(arc_dsp_stat_t *)Bios_GetDisplayStatus(1); #endif } /* * Return geometry of the display. Used by pccons.c to set up the * display configuration. */ void bios_display_info(xpos, ypos, xsize, ysize) int *xpos; int *ypos; int *xsize; int *ysize; { #ifdef __arc__ *xpos = displayinfo.CursorXPosition; *ypos = displayinfo.CursorYPosition; *xsize = displayinfo.CursorMaxXPosition; *ysize = displayinfo.CursorMaxYPosition; #endif }