diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-12-25 22:06:04 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-12-25 22:06:04 +0000 |
commit | 58ece098b90e240e65ec30ecab4cd32e162ec1ba (patch) | |
tree | 0ae294464019a7c02a901504a02579a6bad997ba /sys/arch | |
parent | 624ff93c34cee56288babb7b14d29914ddbc3b96 (diff) |
By popular demand and peer pressure, check-in work in progress work to support
the Yeelong Lemote mips-based netbook. Kernel bits only for now, needs
polishing; most of this work done during h2k9 last month, although the
porting effort started earlier this year.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/loongson/loongson/machdep.c | 944 |
1 files changed, 944 insertions, 0 deletions
diff --git a/sys/arch/loongson/loongson/machdep.c b/sys/arch/loongson/loongson/machdep.c new file mode 100644 index 00000000000..989a92bb584 --- /dev/null +++ b/sys/arch/loongson/loongson/machdep.c @@ -0,0 +1,944 @@ +/* $OpenBSD: machdep.c,v 1.1 2009/12/25 22:06:03 miod Exp $ */ + +/* + * Copyright (c) 2009 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) + * + * 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 AUTHOR ``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 AUTHOR 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/buf.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/msgbuf.h> +#include <sys/tty.h> +#include <sys/user.h> +#include <sys/exec.h> +#include <sys/sysctl.h> +#include <sys/mount.h> +#include <sys/syscallargs.h> +#include <sys/exec_elf.h> +#ifdef SYSVSHM +#include <sys/shm.h> +#endif +#ifdef SYSVSEM +#include <sys/sem.h> +#endif + +#include <uvm/uvm_extern.h> + +#include <machine/db_machdep.h> +#include <ddb/db_interface.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/memconf.h> +#include <machine/pmon.h> + +#include <dev/cons.h> + +#include <mips64/archtype.h> + +#include <loongson/dev/bonitoreg.h> + +/* The following is used externally (sysctl_hw) */ +char machine[] = MACHINE; /* Machine "architecture" */ +char cpu_model[30]; + +/* + * Declare these as initialized data so we can patch them. + */ +#ifndef BUFCACHEPERCENT +#define BUFCACHEPERCENT 5 /* Can be changed in config. */ +#endif +#ifndef BUFPAGES +#define BUFPAGES 0 /* Can be changed in config. */ +#endif +int bufpages = BUFPAGES; +int bufcachepercent = BUFCACHEPERCENT; + +vm_map_t exec_map; +vm_map_t phys_map; + +caddr_t msgbufbase; +vaddr_t uncached_base; + +int physmem; /* Max supported memory, changes to actual. */ +int ncpu = 1; /* At least one CPU in the system. */ +struct user *proc0paddr; +int kbd_reset; + +struct sys_rec sys_config; + +/* Pointers to the start and end of the symbol table. */ +caddr_t ssym; +caddr_t esym; +caddr_t ekern; + +struct phys_mem_desc mem_layout[MAXMEMSEGS]; + +static u_long atoi(const char *, uint); +static void dobootopts(int); + +void build_trampoline(vaddr_t, vaddr_t); +void dumpsys(void); +void dumpconf(void); +vaddr_t mips_init(int32_t, int32_t, int32_t, int32_t); + +extern void loongson2e_setup(u_long, u_long); +extern void loongson2f_setup(u_long, u_long); + +cons_decl(pmon); + +struct consdev pmoncons = { + NULL, + NULL, + pmoncngetc, + pmoncnputc, + nullcnpollc, + NULL, + makedev(0, 0), + CN_DEAD +}; + +/* + * Do all the stuff that locore normally does before calling main(). + * Reset mapping and set up mapping to hardware and init "wired" reg. + */ + +vaddr_t +mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv) +{ + uint prid, loongson_ver; + u_long memlo, memhi, cpuspeed; + vaddr_t xtlb_handler; + const char *envvar; + int i; + + extern char start[], edata[], end[]; + extern char exception[], e_exception[]; + extern char *hw_vendor, *hw_prod; + extern void xtlb_miss; + + /* + * Clear the compiled BSS segment in OpenBSD code. + * PMON is supposed to have done this, though. + */ + + bzero(edata, end - edata); + + /* + * Set up early console output. + */ + + pmon_init(argc, argv, envp, cv); + cn_tab = &pmoncons; + + /* + * Attempt to locate ELF header and symbol table after kernel, + * and reserve space for the symbol table, if it exists. + */ + + ssym = (char *)(vaddr_t)*(int32_t *)end; + if (((long)ssym - (long)end) >= 0 && + ((long)ssym - (long)end) <= 0x1000 && + ssym[0] == ELFMAG0 && ssym[1] == ELFMAG1 && + ssym[2] == ELFMAG2 && ssym[3] == ELFMAG3 ) { + /* Pointers exist directly after kernel. */ + esym = (char *)(vaddr_t)*((int32_t *)end + 1); + ekern = esym; + } else { + /* Pointers aren't setup either... */ + ssym = esym = NULL; + ekern = end; + } + + /* + * 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. + */ + + prid = cp0_get_prid(); + switch ((prid >> 8) & 0xff) { + case MIPS_LOONGSON2: + loongson_ver = 0x2c + (prid & 0xff); + if (loongson_ver == 0x2e || loongson_ver == 0x2f) + break; + /* FALLTHROUGH */ + default: + 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 to figure out what particular machine we run on, depending + * on the PMON version information. + */ + + envvar = pmon_getenv("Version"); + if (envvar == NULL) { + pmon_printf("Unable to figure out model!\n"); + goto unsupported; + } + + /* Lemote Yeelong 8089 */ + if (strncmp(envvar, "LM8089", 6) == 0) { + sys_config.system_type = LOONGSON_YEELONG; + } + + if (sys_config.system_type == 0) { + pmon_printf("This kernel doesn't support model \"%s\".\n", + envvar); + goto unsupported; + } + + switch (sys_config.system_type) { + case LOONGSON_YEELONG: + hw_vendor = "Lemote"; + hw_prod = "Yeelong"; + break; + default: /* won't happen */ + goto unsupported; + } + + pmon_printf("Found %s %s, setting up.\n", hw_vendor, hw_prod); + + snprintf(cpu_model, sizeof cpu_model, "Loongson %X", loongson_ver); + + /* + * Figure out processor clock speed. + * Hopefully the processor speed, in Hertz, will not overflow + * uint32_t... + */ + + cpuspeed = 0; + envvar = pmon_getenv("cpuclock"); + if (envvar != NULL) + cpuspeed = atoi(envvar, 10); /* speed in Hz */ + if (cpuspeed < 100 * 1000000) + cpuspeed = 797000000; /* Reasonable default */ + sys_config.cpu[0].clock = cpuspeed; + + /* + * Look at arguments passed to us and compute boothowto. + */ + + boothowto = RB_AUTOBOOT; + dobootopts(argc); + + /* + * Figure out memory information. + * PMON reports it in two chunks, the memory under the 256MB + * CKSEG limit, and memory above that limit. We need to do the + * math ourselves. + */ + + envvar = pmon_getenv("memsize"); + if (envvar == NULL) { + pmon_printf("Could not get memory information" + " from the firmware\n"); + goto unsupported; + } + memlo = atoi(envvar, 10); /* size in MB */ + if (memlo < 0 || memlo > 256) { + pmon_printf("Incorrect low memory size `%s'\n", envvar); + goto unsupported; + } + + if (memlo == 256) { + envvar = pmon_getenv("highmemsize"); + if (envvar == NULL) + memhi = 0; + else + memhi = atoi(envvar, 10); /* size in MB */ + if (memhi < 0 || memhi > (64 * 1024) - 256) { + pmon_printf("Incorrect high memory size `%s'\n", + envvar); + /* better expose the problem than limit to 256MB */ + goto unsupported; + } + } + + uncached_base = PHYS_TO_XKPHYS(0, CCA_NC); + + switch (loongson_ver) { + case 0x2e: + loongson2e_setup(memlo, memhi); + break; + default: + case 0x2f: + loongson2f_setup(memlo, memhi); + break; + } + + /* + * The above call might have altered address mappings, + * so pmon_printf() should no longer be used from now on. + */ + + /* + * Set pagesize to enable use of page macros and functions. + * Commit available memory to UVM system. + */ + + uvmexp.pagesize = PAGE_SIZE; + uvm_setpagesize(); + + for (i = 0; i < MAXMEMSEGS && mem_layout[i].mem_last_page != 0; i++) { + uint64_t fp, lp; + uint64_t firstkernpage, lastkernpage; + unsigned int freelist; + paddr_t firstkernpa, lastkernpa; + + /* kernel is linked in CKSEG0 */ + firstkernpa = CKSEG0_TO_PHYS((vaddr_t)start); + lastkernpa = CKSEG0_TO_PHYS((vaddr_t)ekern); + if (loongson_ver == 0x2f) { + firstkernpa |= 0x80000000; + lastkernpa |= 0x80000000; + } + + firstkernpage = atop(trunc_page(firstkernpa)); + lastkernpage = atop(round_page(lastkernpa)); + + fp = mem_layout[i].mem_first_page; + lp = mem_layout[i].mem_last_page; + freelist = mem_layout[i].mem_freelist; + + /* Account for kernel and kernel symbol table. */ + if (fp >= firstkernpage && lp < lastkernpage) + continue; /* In kernel. */ + + if (lp < firstkernpage || fp > lastkernpage) { + uvm_page_physload(fp, lp, fp, lp, freelist); + continue; /* Outside kernel. */ + } + + if (fp >= firstkernpage) + fp = lastkernpage; + else if (lp < lastkernpage) + lp = firstkernpage; + else { /* Need to split! */ + uint64_t xp = firstkernpage; + uvm_page_physload(fp, xp, fp, xp, freelist); + fp = lastkernpage; + } + if (lp > fp) { + uvm_page_physload(fp, lp, fp, lp, freelist); + } + } + + sys_config.cpu[0].type = (prid >> 8) & 0xff; + sys_config.cpu[0].vers_maj = (prid >> 4) & 0x0f; + sys_config.cpu[0].vers_min = prid & 0x0f; + /* FPU reports itself as type 5, version 0.1... */ + sys_config.cpu[0].fptype = sys_config.cpu[0].type; + sys_config.cpu[0].fpvers_maj = sys_config.cpu[0].vers_maj; + sys_config.cpu[0].fpvers_min = sys_config.cpu[0].vers_min; + + sys_config.cpu[0].tlbsize = 64; + + /* + * Configure cache. + * Note that the caches being physically tagged, there is no + * need to invalidate or flush it. + */ + + Loongson2_ConfigCache(); + + sys_config.cpu[0].tlbwired = UPAGES / 2; + tlb_set_page_mask(TLB_PAGE_MASK); + tlb_set_wired(0); + tlb_flush(sys_config.cpu[0].tlbsize); + tlb_set_wired(sys_config.cpu[0].tlbwired); + + /* + * Get a console, very early but after initial mapping setup. + */ + + consinit(); + printf("Initial setup done, switching console.\n"); + + /* + * Init message buffer. + */ + + msgbufbase = (caddr_t)pmap_steal_memory(MSGBUFSIZE, NULL,NULL); + initmsgbuf(msgbufbase, MSGBUFSIZE); + + /* + * Allocate U page(s) for proc[0], pm_tlbpid 1. + */ + + proc0.p_addr = proc0paddr = curcpu()->ci_curprocpaddr = + (struct user *)pmap_steal_memory(USPACE, NULL, NULL); + proc0.p_md.md_regs = (struct trap_frame *)&proc0paddr->u_pcb.pcb_regs; + tlb_set_pid(1); + + /* + * Bootstrap VM system. + */ + + pmap_bootstrap(); + + /* + * Copy down exception vector code. + */ + + bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception); + bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception); + + /* + * Build proper TLB refill handler trampolines. + */ + + xtlb_handler = (vaddr_t)&xtlb_miss; + build_trampoline(TLB_MISS_EXC_VEC, xtlb_handler); + + /* + * Turn off bootstrap exception vectors. + * (this is done by PMON already, but it doesn't hurt to be safe) + */ + + setsr(getsr() & ~SR_BOOT_EXC_VEC); + proc0.p_md.md_regs->sr = getsr(); + +#ifdef DDB + db_machine_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif + + /* + * Return the new kernel stack pointer. + */ + + return ((vaddr_t)proc0paddr + USPACE - 64); + +unsupported: + pmon_printf("Halting system.\nPress enter to return to PMON\n"); + cngetc(); + return 0; /* causes us to return to pmon */ +} + +/* + * Build a tlb trampoline + */ +void +build_trampoline(vaddr_t addr, vaddr_t dest) +{ + const uint32_t insns[] = { + 0x3c1a0000, /* lui k0, imm16 */ + 0x675a0000, /* daddiu k0, k0, imm16 */ + 0x001ad438, /* dsll k0, k0, 0x10 */ + 0x675a0000, /* daddiu k0, k0, imm16 */ + 0x001ad438, /* dsll k0, k0, 0x10 */ + 0x675a0000, /* daddiu k0, k0, imm16 */ + 0x03400008, /* jr k0 */ + 0x00000000 /* nop */ + }; + uint32_t *dst = (uint32_t *)addr; + const uint32_t *src = insns; + uint32_t a, b, c, d; + + /* + * Decompose the handler address in the four components which, + * added with sign extension, will produce the correct address. + */ + d = dest & 0xffff; + dest >>= 16; + if (d & 0x8000) + dest++; + c = dest & 0xffff; + dest >>= 16; + if (c & 0x8000) + dest++; + b = dest & 0xffff; + dest >>= 16; + if (b & 0x8000) + dest++; + a = dest & 0xffff; + + /* + * Build the trampoline, skipping noop computations. + */ + *dst++ = *src++ | a; + if (b != 0) + *dst++ = *src++ | b; + else + src++; + *dst++ = *src++; + if (c != 0) + *dst++ = *src++ | c; + else + src++; + *dst++ = *src++; + if (d != 0) + *dst++ = *src++ | d; + else + src++; + *dst++ = *src++; + *dst++ = *src++; + + /* + * Note that we keep the delay slot instruction a nop, instead + * of branching to the second instruction of the handler and + * having its first instruction in the delay slot, so that the + * tlb handler is free to use k0 immediately. + */ +} + +/* + * Decode boot options. + */ +static void +dobootopts(int argc) +{ + const char *arg; + const char *cp; + int ignore = 1; + int i; + + /* + * Parse the boot command line. + * + * It should be of the form `boot [flags] filename [args]', so we + * need to ignore flags to the boot command. + * To achieve this, we ignore argc[0], which is the `boot' command + * itself, and ignore arguments starting with dashes until the + * boot file has been found. + */ + + for (i = 1; i < argc; i++) { + arg = pmon_getarg(i); + if (arg == NULL) + continue; + + if (*arg != '-') { + /* found filename or non-option argument */ + ignore = 0; + continue; + } + + if (ignore) + continue; + + for (cp = arg + 1; *cp != '\0'; cp++) + switch (*cp) { + case '-': + break; + case 'a': + boothowto |= RB_ASKNAME; + break; + case 'c': + boothowto |= RB_CONFIG; + break; + case 'd': + boothowto |= RB_KDB; + break; + case 's': + boothowto |= RB_SINGLE; + break; + default: + pmon_printf("unrecognized option `%c'", *cp); + break; + } + } + + /* + * Consider parsing the `karg' environment variable here too? + */ +} + + +/* + * Console initialization: called early on from main, before vm init or startup. + * Do enough configuration to choose and initialize a console. + */ +void +consinit() +{ + static int console_ok = 0; + + if (console_ok == 0) { + cninit(); + console_ok = 1; + } +} + +/* + * cpu_startup: allocate memory for variable-sized tables, initialize CPU, and + * do auto-configuration. + */ +void +cpu_startup() +{ + vaddr_t minaddr, maxaddr; + + /* + * Good {morning,afternoon,evening,night}. + */ + printf(version); + printf("real mem = %u (%uMB)\n", ptoa(physmem), + ptoa(physmem)/1024/1024); + + /* + * Allocate a submap for exec arguments. This map effectively + * limits the number of processes exec'ing at any time. + */ + minaddr = vm_map_min(kernel_map); + exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, + 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); + /* Allocate a submap for physio. */ + phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, + VM_PHYS_SIZE, 0, FALSE, NULL); + + printf("avail mem = %u (%uMB)\n", ptoa(uvmexp.free), + ptoa(uvmexp.free)/1024/1024); + + /* + * Set up buffers, so they can be used to read disk labels. + */ + bufinit(); + + /* + * Configure the system. + */ + if (boothowto & RB_CONFIG) { +#ifdef BOOT_CONFIG + user_config(); +#else + printf("kernel does not support -c; continuing..\n"); +#endif + } +} + +/* + * Machine dependent system variables. + */ +int +cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + /* All sysctl names at this level are terminal. */ + if (namelen != 1) + return ENOTDIR; /* Overloaded */ + + switch (name[0]) { + case CPU_KBDRESET: + if (securelevel > 0) + return (sysctl_rdint(oldp, oldlenp, newp, kbd_reset)); + return (sysctl_int(oldp, oldlenp, newp, newlen, &kbd_reset)); + default: + return EOPNOTSUPP; + } +} + +/* + * Set registers on exec for native exec format. For o64/64. + */ +void +setregs(p, pack, stack, retval) + struct proc *p; + struct exec_package *pack; + u_long stack; + register_t *retval; +{ + extern struct proc *machFPCurProcPtr; + + bzero((caddr_t)p->p_md.md_regs, sizeof(struct trap_frame)); + p->p_md.md_regs->sp = stack; + p->p_md.md_regs->pc = pack->ep_entry & ~3; + p->p_md.md_regs->t9 = pack->ep_entry & ~3; /* abicall req */ + p->p_md.md_regs->sr = SR_FR_32 | SR_XX | SR_KSU_USER | SR_KX | SR_UX | + SR_EXL | SR_INT_ENAB; + p->p_md.md_regs->sr |= idle_mask & SR_INT_MASK; + p->p_md.md_regs->ic = (idle_mask << 8) & IC_INT_MASK; + p->p_md.md_flags &= ~MDP_FPUSED; + if (machFPCurProcPtr == p) + machFPCurProcPtr = NULL; + p->p_md.md_ss_addr = 0; + p->p_md.md_pc_ctrl = 0; + p->p_md.md_watch_1 = 0; + p->p_md.md_watch_2 = 0; + + retval[1] = 0; +} + + +int waittime = -1; + +void +boot(int howto) +{ + + /* Take a snapshot before clobbering any registers. */ + if (curproc) + savectx(curproc->p_addr, 0); + + if (cold) { + /* + * If the system is cold, just halt, unless the user + * explicitly asked for reboot. + */ + if ((howto & RB_USERREQ) == 0) + howto |= RB_HALT; + goto haltsys; + } + + boothowto = howto; + if ((howto & RB_NOSYNC) == 0 && waittime < 0) { + extern struct proc proc0; + /* fill curproc with live object */ + if (curproc == NULL) + curproc = &proc0; + /* + * Synchronize the disks... + */ + waittime = 0; + vfs_shutdown(); + + /* + * If we've been adjusting the clock, the todr will be out of + * sync; adjust it now. + */ + if ((howto & RB_TIMEBAD) == 0) { + resettodr(); + } else { + printf("WARNING: not updating battery clock\n"); + } + } + + uvm_shutdown(); + (void) splhigh(); /* Extreme priority. */ + + if (howto & RB_DUMP) + dumpsys(); + +haltsys: + doshutdownhooks(); + + if (howto & RB_HALT) { + if (howto & RB_POWERDOWN) { + printf("System Power Down.\n"); + REGVAL(BONITO_GPIODATA) &= ~0x00000001; + REGVAL(BONITO_GPIOIE) &= ~0x00000001; + } else + printf("System Halt.\n"); + } else { + void (*__reset)(void) = (void (*)(void))RESET_EXC_VEC; + printf("System restart.\n"); + __reset(); + } + + for (;;) ; + /*NOTREACHED*/ +} + +u_long dumpmag = 0x8fca0101; /* Magic number for savecore. */ +int dumpsize = 0; /* Also for savecore. */ +long dumplo = 0; + +void +dumpconf(void) +{ + int nblks; + + if (dumpdev == NODEV || + (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0) + return; + if (nblks <= ctod(1)) + return; + + dumpsize = ptoa(physmem); + if (dumpsize > atop(round_page(dbtob(nblks - dumplo)))) + dumpsize = atop(round_page(dbtob(nblks - dumplo))); + else if (dumplo == 0) + dumplo = nblks - btodb(ptoa(physmem)); + + /* + * Don't dump on the first page in case the dump device includes a + * disk label. + */ + if (dumplo < btodb(PAGE_SIZE)) + dumplo = btodb(PAGE_SIZE); +} + +void +dumpsys() +{ + /* XXX TBD */ +} + +/* + * Convert an ASCII string into an integer. + */ +static u_long +atoi(const char *s, uint b) +{ + int c; + uint base = b, d; + int neg = 0; + u_long val = 0; + + if (s == NULL || *s == '\0') + return 0; + + /* Skip spaces if any. */ + do { + c = *s++; + } while (c == ' ' || c == '\t'); + + /* Parse sign, allow more than one (compat). */ + while (c == '-') { + neg = !neg; + c = *s++; + } + + /* Parse base specification, if any. */ + if (base == 0 && c == '0') { + c = *s++; + switch (c) { + case 'X': + case 'x': + base = 16; + c = *s++; + break; + case 'B': + case 'b': + base = 2; + c = *s++; + break; + default: + base = 8; + break; + } + } + + /* Parse number proper. */ + for (;;) { + if (c >= '0' && c <= '9') + d = c - '0'; + else if (c >= 'a' && c <= 'z') + d = c - 'a' + 10; + else if (c >= 'A' && c <= 'Z') + d = c - 'A' + 10; + else + break; + if (d >= base) + break; + val *= base; + val += d; + c = *s++; + } + + return neg ? -val : val; +} + +/* + * Early console through pmon routines. + */ + +int +pmoncngetc(dev_t dev) +{ + /* + * PMON does not give us a getc routine. So try to get a whole line + * and return it char by char, trying not to lose the \n. Kind + * of ugly but should work. + */ + static char buf[1 + PMON_MAXLN]; + static char *bufpos = buf; + int c; + + if (*bufpos == '\0') { + bufpos = buf; + if (pmon_gets(buf) == NULL) { + /* either an empty line or EOF. assume the former */ + return (int)'\n'; + } else { + /* put back the \n sign */ + buf[strlen(buf)] = '\n'; + } + } + + c = (int)*bufpos++; + if (bufpos - buf > PMON_MAXLN) { + bufpos = buf; + *bufpos = '\0'; + } + + return c; +} + +void +pmoncnputc(dev_t dev, int c) +{ + if (c == '\n') + pmon_printf("\n"); + else + pmon_printf("%c", c); +} |