code:
/*	$OpenBSD: loongson2_machdep.c,v 1.15 2014/03/27 21:58:57 miod Exp $	*/

/*
 * Copyright (c) 2009, 2010 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.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/sysctl.h>

#include <uvm/uvm_extern.h>

#include <machine/autoconf.h>
#include <machine/cpu.h>
#include <machine/loongson2.h>
#include <machine/memconf.h>
#include <machine/pmon.h>

#ifdef HIBERNATE
#include <machine/hibernate_var.h>
#endif /* HIBERNATE */

#include <loongson/dev/bonitoreg.h>

extern struct phys_mem_desc mem_layout[MAXMEMSEGS];

boolean_t is_memory_range(paddr_t, psize_t, psize_t);
void	loongson2e_setup(u_long, u_long);
void	loongson2f_setup(u_long, u_long);
void	loongson2f_setup_window(uint, uint, uint64_t, uint64_t, uint64_t, uint);

/* PCI view of CPU memory */
paddr_t loongson_dma_base = 0;

/*
 * Canonical crossbow assignments on Loongson 2F based designs.
 * Might need to move to a per-design header file in the future.
 */

#define	MASTER_CPU		0
#define	MASTER_PCI		1

#define	WINDOW_CPU_LOW		0
#define	WINDOW_CPU_PCILO	1
#define	WINDOW_CPU_PCIHI	2
#define	WINDOW_CPU_DDR		3

#define	WINDOW_PCI_DDR		0

#define	DDR_PHYSICAL_BASE	0x0000000000000000UL	/* memory starts at 0 */
#define	DDR_PHYSICAL_SIZE	0x0000000080000000UL	/* up to 2GB */
#define	DDR_WINDOW_BASE		0x0000000080000000UL	/* mapped at 2GB */

#define	PCI_RESOURCE_BASE	0x0000000000000000UL
#define	PCI_RESOURCE_SIZE	0x0000000080000000UL

#define	PCI_DDR_BASE		0x0000000080000000UL	/* PCI->DDR at 2GB */

/*
 * Setup memory mappings for Loongson 2E processors.
 */

void
loongson2e_setup(u_long memlo, u_long memhi)
{
	if (memhi > ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20)) {
		pmon_printf("WARNING! %d MB of memory will not be used",
		    memhi - ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20));
		memhi = (DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20;
	}

	memlo = atop(memlo << 20);
	memhi = atop(memhi << 20);
	physmem = memlo + memhi;

	/* do NOT stomp on exception area */
	mem_layout[0].mem_first_page = atop(DDR_PHYSICAL_BASE) + 1;
	mem_layout[0].mem_last_page = atop(DDR_PHYSICAL_BASE) + memlo;

	if (memhi != 0) {
		mem_layout[1].mem_first_page = atop(BONITO_PCIHI_BASE);
		mem_layout[1].mem_last_page = atop(BONITO_PCIHI_BASE) +
		    memhi;
	}

	loongson_dma_base = PCI_DDR_BASE ^ DDR_PHYSICAL_BASE;
}

/*
 * Setup memory mappings for Loongson 2F processors.
 */

void
loongson2f_setup(u_long memlo, u_long memhi)
{
	/*
	 * Because we'll only set up a 2GB window for the PCI bus to
	 * access local memory, we'll limit ourselves to 2GB of usable
	 * memory as well.
	 *
	 * Note that this is a bad justification for this; it should be
	 * possible to setup a 1GB PCI space / 3GB memory access window,
	 * and use bounce buffers if physmem > 3GB; but at the moment
	 * there is no need to solve this problem until Loongson 2F-based
	 * hardware with more than 2GB of memory is commonly encountered.
	 *
	 * Also note that, despite the crossbar window registers being
	 * 64-bit wide, the upper 32-bit always read back as zeroes, so
	 * it is dubious whether it is possible to use more than a 4GB
	 * address space... and thus more than 2GB of physical memory.
	 */

	physmem = memlo + memhi;	/* in MB so far */
	if (physmem > (DDR_PHYSICAL_SIZE >> 20)) {
		pmon_printf("WARNING! %d MB of memory will not be used",
		    physmem - (DDR_PHYSICAL_SIZE >> 20));
		memhi = (DDR_PHYSICAL_SIZE >> 20) - 256;
	}

	memlo = atop(memlo << 20);
	memhi = atop(memhi << 20);
	physmem = memlo + memhi;

	/*
	 * PMON configures the system with only the low 256MB of memory
	 * accessible.
	 *
	 * We need to reprogram the address windows in order to be able to
	 * access the whole memory, both by the local processor and by the
	 * PCI bus.
	 *
	 * To make our life easier, we'll setup the memory as a contiguous
	 * range starting at 2GB, and take into account the fact that the
	 * first 256MB are also aliased at address zero (which is where the
	 * kernel is loaded, really).
	 */

	if (memhi != 0) {
		/* do NOT stomp on exception area */
		mem_layout[0].mem_first_page = atop(DDR_WINDOW_BASE) + 1;
		mem_layout[0].mem_last_page = atop(DDR_WINDOW_BASE) +
		    memlo + memhi;
		loongson_dma_base = PCI_DDR_BASE ^ DDR_WINDOW_BASE;
	} else {
		/* do NOT stomp on exception area */
		mem_layout[0].mem_first_page = atop(DDR_PHYSICAL_BASE) + 1;
		mem_layout[0].mem_last_page = atop(DDR_PHYSICAL_BASE) +
		    memlo /* + memhi */;
		loongson_dma_base = PCI_DDR_BASE ^ DDR_PHYSICAL_BASE;
	}
#ifdef HIBERNATE
	mem_layout[0].mem_first_page += HIBERNATE_RESERVED_PAGES;
#endif

	/*
	 * Allow access to memory beyond 256MB, by programming the
	 * Loongson 2F address window registers.
	 * This also makes sure PCI->DDR accesses can use a contiguous
	 * area regardless of the actual memory size.
	 */

	/*
	 * Master #0 (cpu) window #0 allows access to the low 256MB
	 * of memory at address zero onwards.
	 * This window is inherited from PMON; we set it up just in case.
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_LOW, DDR_PHYSICAL_BASE,
	    ~(0x0fffffffUL), DDR_PHYSICAL_BASE, MASTER_CPU);

	/*
	 * Master #0 (cpu) window #1 allows access to the ``low'' PCI
	 * space (from 0x10000000 to 0x1fffffff).
	 * This window is inherited from PMON; we set it up just in case.
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCILO, BONITO_PCILO_BASE,
	    ~(0x0fffffffUL), BONITO_PCILO_BASE, MASTER_PCI);

	/*
	 * Master #1 (PCI) window #0 allows access to the memory space
	 * by PCI devices at addresses 0x80000000 onwards.
	 * This window is inherited from PMON, but its mask might be too
	 * restrictive (256MB) so we make sure it matches our needs.
	 */
	loongson2f_setup_window(MASTER_PCI, WINDOW_PCI_DDR, PCI_DDR_BASE,
	    ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);

	/*
	 * Master #0 (CPU) window #2 allows access to a subset of the ``high''
	 * PCI space (from 0x40000000 to 0x7fffffff only).
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCIHI, LS2F_PCIHI_BASE,
	    ~((uint64_t)LS2F_PCIHI_SIZE - 1), LS2F_PCIHI_BASE, MASTER_PCI);

	/*
	 * Master #0 (CPU) window #3 allows access to the whole memory space
	 * at addresses 0x80000000 onwards.
	 */
	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_DDR, DDR_WINDOW_BASE,
	    ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);

	cpu_cpuspeed = loongson2f_cpuspeed;
}

/*
 * Setup a window in the Loongson2F crossbar.
 */

void
loongson2f_setup_window(uint master, uint window, uint64_t base, uint64_t mask,
    uint64_t mmap, uint slave)
{
	volatile uint64_t *awrreg;

	awrreg = (volatile uint64_t *)PHYS_TO_XKPHYS(
	    LOONGSON_AWR_BASE(master, window), CCA_NC);
	*awrreg = base;
	(void)*awrreg;

	awrreg = (volatile uint64_t *)PHYS_TO_XKPHYS(
	    LOONGSON_AWR_SIZE(master, window), CCA_NC);
	*awrreg = mask;
	(void)*awrreg;

	awrreg = (volatile uint64_t *)PHYS_TO_XKPHYS(
	    LOONGSON_AWR_MMAP(master, window), CCA_NC);
	*awrreg = mmap | slave;
	(void)*awrreg;
}

/*
 * Return whether a given physical address points to managed memory.
 * (used by /dev/mem)
 */

boolean_t
is_memory_range(paddr_t pa, psize_t len, psize_t limit)
{
	struct phys_mem_desc *seg;
	uint64_t fp, lp;
	int i;

	fp = atop(pa);
	lp = atop(round_page(pa + len));

	if (limit != 0 && lp > atop(limit))
		return FALSE;

	/*
	 * Allow access to the low 256MB aliased region on 2F systems,
	 * if we are accessing memory at 2GB onwards.
	 */
	if (pa < 0x10000000 && loongson_ver >= 0x2f) {
		fp += mem_layout[0].mem_first_page - 1;
		lp += mem_layout[0].mem_first_page - 1;
	}

	for (i = 0, seg = mem_layout; i < MAXMEMSEGS; i++, seg++)
		if (fp >= seg->mem_first_page && lp <= seg->mem_last_page)
			return TRUE;

	return FALSE;
}

int
loongson2f_cpuspeed(int *freq)
{
	uint32_t step, val;

	val = REGVAL(LOONGSON_CHIP_CONFIG0);
	step = (val & 0x7) + 1;
	*freq = ((bootcpu_hwinfo.clock / 8) * step) / 1000000;

	return 0;
}

void
loongson2f_setperf(int percent)
{
	uint32_t step, val;

	step = percent * 8 / 100;
	if (step < 2)
		step = 2;

	/*
	 * Set clock step.
	 */
	val = REGVAL(LOONGSON_CHIP_CONFIG0);
	val = (val & ~0x7) | (step - 1);
	REGVAL(LOONGSON_CHIP_CONFIG0) = val;
	(void)REGVAL(LOONGSON_CHIP_CONFIG0);
}


code:
/*	$OpenBSD: machdep.c,v 1.63 2015/05/07 01:55:43 jsg Exp $ */

/*
 * 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
 * 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 <net/if.h>

#include <uvm/uvm_extern.h>

#include <machine/db_machdep.h>
#include <ddb/db_interface.h>

#include <machine/autoconf.h>
#include <mips64/cache.h>
#include <machine/cpu.h>
#include <mips64/mips_cpu.h>
#include <machine/memconf.h>
#include <machine/pmon.h>

#ifdef HIBERNATE
#include <machine/hibernate_var.h>
#endif /* HIBERNATE */

#include <dev/cons.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

/* The following is used externally (sysctl_hw) */
char	machine[] = MACHINE;		/* Machine "architecture" */
char	cpu_model[30];
char	pmon_bootp[80];

/*
 * 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 };

vm_map_t exec_map;
vm_map_t phys_map;

/*
 * safepri is a safe priority for sleep to set for a spin-wait
 * during autoconfiguration or after a panic.
 */
int   safepri = 0;

caddr_t	msgbufbase;

int	physmem;		/* Max supported memory, changes to actual. */
int	ncpu = 1;		/* At least one CPU in the system. */
struct	user *proc0paddr;

const struct platform *sys_platform;
struct cpu_hwinfo bootcpu_hwinfo;
uint loongson_ver;

/* 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];

pcitag_t (*pci_make_tag_early)(int, int, int);
pcireg_t (*pci_conf_read_early)(pcitag_t, int);
bus_space_tag_t early_mem_t;
bus_space_tag_t early_io_t;

static u_long atoi(const char *, uint);
static void dobootopts(int);

void	dumpsys(void);
void	dumpconf(void);
extern	void parsepmonbp(void);
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);

struct consdev pmoncons = {
	NULL,
	NULL,
	pmoncngetc,
	pmoncnputc,
	nullcnpollc,
	NULL,
	makedev(0, 0),
	CN_DEAD
};

/*
 * List of supported system types, from the ``Version'' environment
 * variable.
 */

struct bonito_flavour {
	const char *prefix;
	const struct platform *platform;
};

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 */
	{ "LM6002",	&fuloong_platform },	/* dual Ethernet,
						   prefix added by user */
	{ "LM6003",	&fuloong_platform },
	{ "LM6004",	&fuloong_platform },
	/* EMTEC Gdium Liberty 1000 */
	{ "Gdium",	&gdium_platform },
	/* Lemote Yeeloong 8.9" netbook */
	{ "LM8089",	&yeeloong_platform },
	/* supposedly Lemote Yeeloong 10.1" netbook, but those found so far
	   report themselves as LM8089 */
	{ "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 }
};

/*
 * Try to figure out what particular machine we run on, depending on the
 * scarce PMON version information and whatever else we can figure.
 */
const struct platform *
loongson_identify(const char *version, int envtype)
{
	const struct bonito_flavour *f;

	switch (envtype) {
	case PMON_ENVTYPE_EFI:
		return NULL;
		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;
			}
		}

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

	pmon_printf("This kernel doesn't support model \"%s\"." "\n", version);
	return NULL;
}

/*
 * 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(uint64_t argc, uint64_t argv, uint64_t envp, uint64_t cv,
    char *boot_esym)
{
	uint32_t prid;
	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;

	/*
	 * Make sure we can access the extended address space.
	 * This is not necessary on real hardware, but some emulators
	 * are not aware of this.
	 */
	setsr(getsr() | SR_KX | SR_UX);

	/*
	 * 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.
	 */

	prid = cp0_get_prid();
	pmon_init((int32_t)argc, (int32_t)argv, (int32_t)envp, (int32_t)cv,
	    prid);
	cn_tab = &pmoncons;

	/*
	 * Reserve space for the symbol table, if it exists.
	 */

	/* Attempt to locate ELF header and symbol table after kernel. */
	if (end[0] == ELFMAG0 && end[1] == ELFMAG1 &&
	    end[2] == ELFMAG2 && end[3] == ELFMAG3) {
		/* ELF header exists directly after kernel. */
		ssym = end;
		esym = boot_esym;
		ekern = esym;
	} else {
		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 = NULL;
			esym = NULL;
			ekern = end;
		}
	}

	/*
	 * While the kernel supports other processor types than Loongson,
	 * 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.
	 */

	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;
#endif
		default:
			break;
		}
	}
	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"),
	    pmon_getenvtype())) == NULL)
		goto unsupported;

	hw_vendor = sys_platform->vendor;
	hw_prod = sys_platform->product;
	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 */
	bootcpu_hwinfo.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;
	}

	/* 3A PMON only reports up to 240MB as low memory */
	if (memlo >= 240) {
		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;
		}
	} else
		memhi = 0;

	switch (loongson_ver) {
	default:
#ifdef CPU_LOONGSON2
	case 0x2e:
		loongson2e_setup(memlo, memhi);
		break;
	case 0x2f:
		loongson2f_setup(memlo, memhi);
		break;
#endif
#ifdef CPU_LOONGSON3
	case 0x3a:
		loongson3a_setup(memlo, memhi);
		break;
#endif
	}

	if (sys_platform->setup != NULL)
		(*(sys_platform->setup))();

	/*
	 * PMON functions 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;
		paddr_t firstkernpa, lastkernpa;

		/* kernel is linked in CKSEG0 */
		firstkernpa = CKSEG0_TO_PHYS((vaddr_t)start);
		lastkernpa = CKSEG0_TO_PHYS((vaddr_t)ekern);

		firstkernpage = atop(trunc_page(firstkernpa)) +
		    mem_layout[0].mem_first_page - 1;
#ifdef HIBERNATE
		firstkernpage -= HIBERNATE_RESERVED_PAGES;
#endif
		lastkernpage = atop(round_page(lastkernpa)) +
		    mem_layout[0].mem_first_page - 1;

		fp = mem_layout[i].mem_first_page;
		lp = mem_layout[i].mem_last_page;

		/* 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, 0);
			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, 0);
			fp = lastkernpage;
		}
		if (lp > fp) {
			uvm_page_physload(fp, lp, fp, lp, 0);
		}
	}

	bootcpu_hwinfo.c0prid = prid;
	bootcpu_hwinfo.type = (prid >> 8) & 0xff;
	/* FPU reports itself as type 5, version 0.1... */
	bootcpu_hwinfo.c1prid = bootcpu_hwinfo.c0prid;

	/*
	 * Configure cache and tlb.
	 */

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

	/*
	 * Get a console, very early but after initial mapping setup.
	 */

	consinit();
	printf("Initial setup done, switching console.\n");

	/*
	 * Init message buffer. This is similar to pmap_steal_memory(), but
	 * without zeroing the area, to keep the message buffer from the
	 * previous kernel run intact, if any.
	 */
	for (i = 0; i < vm_nphysseg; i++) {
		struct vm_physseg *vps = &vm_physmem[i];
		uint npg = atop(round_page(MSGBUFSIZE));
		int j;

		if (vps->avail_start != vps->start ||
		    vps->avail_start >= vps->avail_end) {
			continue;
		}

		if ((vps->avail_end - vps->avail_start) < npg)
			continue;

		msgbufbase = (caddr_t)PHYS_TO_XKPHYS(ptoa(vps->avail_start),
		    CCA_CACHED);
		vps->avail_start += npg;
		vps->start += npg;

		if (vps->avail_start == vps->end) {
			/* don't bother panicing if nphysseg becomes zero, */
			/* the next pmap_steal_memory() call will. */
			vm_nphysseg--;
			for (j = i; j < vm_nphysseg; j++)
				vm_physmem[j] = vm_physmem[j + 1];
		}

		break;
	}
	if (msgbufbase == NULL)
		panic("not enough contiguous memory for message buffer");
	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(MIN_USER_ASID);

	/*
	 * 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 */
}

/*
 * 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.
	 */

	if (argc != 0) {
		arg = pmon_getarg(0);
		if (arg == NULL)
			return;
		/* if `go', not `boot', then no path and command options */
		if (*arg == 'g')
			ignore = 0;
	}
	for (i = 1; i < argc; i++) {
		arg = pmon_getarg(i);
		if (arg == NULL)
			continue;

		/* device path */
		if (*arg == '/' || strncmp(arg, "tftp://", 7) == 0) {
			if (*pmon_bootp == '\0') {
				strlcpy(pmon_bootp, arg, sizeof pmon_bootp);
				parsepmonbp();
			}
			ignore = 0;	/* further options are for the kernel */
			continue;
		}

		/* not an option, or not a kernel option */
		if (*arg != '-' || 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) {
		cn_tab = NULL;
		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 = %lu (%luMB)\n", ptoa((psize_t)physmem),
	    ptoa((psize_t)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 = %lu (%luMB)\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]) {
	default:
		return EOPNOTSUPP;
	}
}

int	waittime = -1;

__dead void
boot(int howto)
{
	if (curproc)
		savectx(curproc->p_addr, 0);

	if (cold) {
		if ((howto & RB_USERREQ) == 0)
			howto |= RB_HALT;
		goto haltsys;
	}

	boothowto = howto;
	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
		waittime = 0;
		vfs_shutdown();

		if ((howto & RB_TIMEBAD) == 0) {
			resettodr();
		} else {
			printf("WARNING: not updating battery clock\n");
		}
	}
	if_downall();

	uvm_shutdown();
	splhigh();
	cold = 1;

	if ((howto & RB_DUMP) != 0)
		dumpsys();

haltsys:
	pci_dopm = 0;
	config_suspend_all(DVACT_POWERDOWN);

	if ((howto & RB_HALT) != 0) {
		if ((howto & RB_POWERDOWN) != 0) {
			if (sys_platform->powerdown != NULL) {
				printf("System Power Down.\n");
				(*(sys_platform->powerdown))();
			} else {
				printf("System Power Down not supported,"
				    " halting system.\n");
			}
		} else
			printf("System Halt.\n");
	} else {
		void (*__reset)(void) = (void (*)(void))RESET_EXC_VEC;
		printf("System restart.\n");
		if (sys_platform->reset != NULL)
			(*(sys_platform->reset))();
		(void)disableintr();
		tlb_set_wired(0);
		tlb_flush(bootcpu_hwinfo.tlbsize);
		__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.
	 *
	 * Note that one could theoretically use pmon_read(STDIN, &c, 1)
	 * but the value of STDIN within PMON is not a constant and there
	 * does not seem to be a way of letting us know which value to use.
	 */
	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);
}

license: unknown


code:
/*	$OpenBSD: pciide_machdep.c,v 1.2 2010/05/08 21:59:56 miod Exp $	*/
/*	$NetBSD: pciide_machdep.c,v 1.2 1999/02/19 18:01:27 mycroft Exp $	*/

/*
 * Copyright (c) 1998 Christopher G. Demetriou.  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.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Christopher G. Demetriou
 *	for the NetBSD Project.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * 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.
 */

/*
 * PCI IDE controller driver (i386 machine-dependent portion).
 *
 * Author: Christopher G. Demetriou, March 2, 1998 (derived from NetBSD
 * sys/dev/pci/ppb.c, revision 1.16).
 *
 * See "PCI IDE Controller Specification, Revision 1.0 3/4/94" from the
 * PCI SIG.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pciidereg.h>
#include <dev/pci/pciidevar.h>

#include <machine/autoconf.h>

#include <dev/isa/isavar.h>

void *
pciide_machdep_compat_intr_establish(struct device *dev,
    struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
{
	int irq;
	void *cookie;

	if (sys_platform->isa_chipset != NULL) {
		irq = PCIIDE_COMPAT_IRQ(chan);
		cookie = isa_intr_establish(sys_platform->isa_chipset,
		    irq, IST_EDGE, IPL_BIO, func, arg, dev->dv_xname);
	} else
		cookie = NULL;

	return (cookie);
}

void
pciide_machdep_compat_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
{
	if (sys_platform->isa_chipset != NULL)
		isa_intr_disestablish(sys_platform->isa_chipset, cookie);
}


code:
/*	$OpenBSD: pmon.c,v 1.5 2014/03/29 23:59:49 miod Exp $	*/

/*
 * 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
 * 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.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>

#include <machine/cpu.h>
#include <machine/pmon.h>

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,
    uint32_t prid)
{
	pmon_callvec = callvec;

	pmon_argc = argc;
	/* 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 *
pmon_getarg(const int argno)
{
	if (argno < 0 || argno >= pmon_argc)
		return NULL;

	return (const char *)(vaddr_t)pmon_argv[argno];
}

int
pmon_getenvtype()
{
	return pmon_envtype;
}

const char *
pmon_getenv(const char *var)
{
	int32_t *envptr = pmon_envp;
	const char *envstr;
	size_t varlen;

	if (envptr == NULL || pmon_envtype != PMON_ENVTYPE_ENVP)
		return NULL;

	varlen = strlen(var);
	while (*envptr != 0) {
		envstr = (const char *)(vaddr_t)*envptr;
		/*
		 * There is a PMON2000 bug, at least on Lemote Yeeloong,
		 * which causes it to override part of the environment
		 * pointers array with the environment data itself.
		 *
		 * This only happens on cold boot, and if the BSD kernel
		 * is loaded without symbols (i.e. no option -k passed
		 * to the boot command).
		 *
		 * Until a suitable workaround is found or the bug is
		 * fixed, ignore broken environment information and
		 * tell the user (in case this prevents us from finding
		 * important information).
		 */
		if ((vaddr_t)envstr - pmon_envbase >= CKSEG_SIZE) {
			printf("WARNING! CORRUPTED ENVIRONMENT!\n");
			printf("Unable to search for \"%s\".\n", var);
#ifdef _STANDALONE
			printf("If boot fails, power-cycle the machine.\n");
#else
			printf("If the kernel fails to identify the system"
			    " type, please boot it again with `-k' option.\n");
#endif

			/* terminate environment for further calls */
			*envptr = 0;
			break;
		}
		if (strncmp(envstr, var, varlen) == 0 &&
		    envstr[varlen] == '=')
			return envstr + varlen + 1;
		envptr++;
	}

	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);
}


code:
/*	$OpenBSD: pmon32.S,v 1.4 2010/02/18 18:53:33 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.
 */

/*
 * Wrapper routines to invoke PMON2000 functions from 64-bit code.
 *
 * PMON is compiled as 64 bit code, using the gcc o64 ABI (similar to the o32
 * ABI, but using 64 bit registers).
 *
 * As a result, only up to four arguments to functions will be passed through
 * registers.  It's up to the caller to never invoke pmon_printf() with more
 * than four arguments; other functions are not affected.
 */

#include <machine/param.h>
#include <machine/asm.h>

#ifndef _STANDALONE
#include "assym.h"
#endif

	.set	mips3

	.data
	.globl	pmon_callvec
pmon_callvec:
	.word	0

	.text

/*
 * Note that we need to provide a CF_SZ untouched area above sp, or we'll risk
 * our stack being corrupted upon return.
 */
#define	PMON_WRAP(name, index) \
	NNON_LEAF(name, FRAMESZ(CF_SZ + 9 * REGSZ),  ra); \
	PTR_SUBU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ); \
	REG_S	ra, CF_RA_OFFS(sp); \
	.mask	0xc0ff0000, (CF_RA_OFFS - FRAMESZ(CF_SZ + 9 * REGSZ)); \
	REG_S	s0, (0 * REGSZ + CF_SZ)(sp); \
	REG_S	s1, (1 * REGSZ + CF_SZ)(sp); \
	REG_S	s2, (2 * REGSZ + CF_SZ)(sp); \
	REG_S	s3, (3 * REGSZ + CF_SZ)(sp); \
	REG_S	s4, (4 * REGSZ + CF_SZ)(sp); \
	REG_S	s5, (5 * REGSZ + CF_SZ)(sp); \
	REG_S	s6, (6 * REGSZ + CF_SZ)(sp); \
	REG_S	s7, (7 * REGSZ + CF_SZ)(sp); \
	REG_S	s8, (8 * REGSZ + CF_SZ)(sp); \
	lw	t0, pmon_callvec; \
	lw	t0, (index) * 4 (t0); \
	jalr	t0; \
	nop; \
	REG_L	s8, (8 * REGSZ + CF_SZ)(sp); \
	REG_L	s7, (7 * REGSZ + CF_SZ)(sp); \
	REG_L	s6, (6 * REGSZ + CF_SZ)(sp); \
	REG_L	s5, (5 * REGSZ + CF_SZ)(sp); \
	REG_L	s4, (4 * REGSZ + CF_SZ)(sp); \
	REG_L	s3, (3 * REGSZ + CF_SZ)(sp); \
	REG_L	s2, (2 * REGSZ + CF_SZ)(sp); \
	REG_L	s1, (1 * REGSZ + CF_SZ)(sp); \
	REG_L	s0, (0 * REGSZ + CF_SZ)(sp); \
	REG_L	ra, CF_RA_OFFS(sp); \
	PTR_ADDU sp, sp, FRAMESZ(CF_SZ + 9 * REGSZ); \
	jr	ra; \
	nop; \
	END(name)

PMON_WRAP(pmon_printf, 5)
PMON_WRAP(pmon_gets, 7)
#ifdef _STANDALONE
PMON_WRAP(pmon_open, 0)
PMON_WRAP(pmon_close, 1)
PMON_WRAP(pmon_read, 2)
PMON_WRAP(pmon_lseek, 4)
PMON_WRAP(pmon_cacheflush, 6)
#endif
#if 0	/* unused */
PMON_WRAP(pmon_write, 3)
#endif


code:
/*	$OpenBSD: wscons_machdep.c,v 1.11 2014/03/27 22:16:03 miod Exp $ */

/*
 * Copyright (c) 2010 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) 2001 Aaron Campbell
 * 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 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 OR HIS RELATIVES 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 MIND, 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/conf.h>
#include <sys/device.h>
#include <sys/extent.h>

#include <machine/autoconf.h>
#include <machine/bus.h>

#include <dev/cons.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/vga_pcivar.h>

#include "wsdisplay.h"
#if NWSDISPLAY > 0
#include <dev/wscons/wsdisplayvar.h>
#endif
#include "sisfb.h"
extern int sisfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t);
#include "smfb.h"
extern int smfb_cnattach(bus_space_tag_t, bus_space_tag_t, pcitag_t, pcireg_t);
#include "vga.h"

#include "pckbc.h"
#if NPCKBC > 0
#include <dev/isa/isareg.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#endif
#include "pckbd.h"
#include "ukbd.h"
#if NUKBD > 0
#include <dev/usb/ukbdvar.h>
#endif
#if NPCKBD > 0 || NUKBD > 0
#include <dev/wscons/wskbdvar.h>
#endif

cons_decl(ws);

void
wscnprobe(struct consdev *cp)
{
	pcitag_t tag;
	pcireg_t id, class;
	int maj, dev;

	cp->cn_pri = CN_DEAD;

	/* Locate the major number. */
	for (maj = 0; maj < nchrdev; maj++) {
		if (cdevsw[maj].d_open == wsdisplayopen)
			break;
	}

	if (maj == nchrdev) {
		/* We are not in cdevsw[], give up. */
		return;
	}

	/*
	 * Look for a suitable video device.
	 */

	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;

		class = pci_conf_read_early(tag, PCI_CLASS_REG);
		if (!DEVICE_IS_VGA_PCI(class) &&
		    !(PCI_CLASS(class) == PCI_CLASS_DISPLAY &&
		      PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_MISC))
			continue;

		cp->cn_dev = makedev(maj, 0);
		cp->cn_pri = CN_MIDPRI;
		break;
	}
}

void
wscninit(struct consdev *cp)
{
static	int initted;
	pcitag_t tag;
	pcireg_t id, class;
	int dev, rc;
	extern struct consdev pmoncons;

	if (initted)
		return;

	initted = 1;

	cn_tab = &pmoncons;	/* to be able to panic */

	/*
	 * Look for a suitable video device.
	 */

	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;

		class = pci_conf_read_early(tag, PCI_CLASS_REG);
		if (!DEVICE_IS_VGA_PCI(class) &&
		    !(PCI_CLASS(class) == PCI_CLASS_DISPLAY &&
		      PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_MISC))
			continue;

		/*
		 * Try to configure this device as glass console.
		 */

		rc = ENXIO;

		/* bitmapped frame buffer won't be of PREHISTORIC class */
		if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) {
#if NSISFB > 0
			if (rc != 0 && early_io_t != NULL)
				rc = sisfb_cnattach(early_mem_t,
				    early_io_t, tag, id);
#endif
#if NSMFB > 0
			if (rc != 0 && early_io_t != NULL)
				rc = smfb_cnattach(early_mem_t,
				    early_io_t, tag, id);
#endif
			}
#if NVGA > 0
		if (rc != 0 && early_io_t != NULL) {
			/* thanks $DEITY the pci_chipset_tag_t arg is ignored */
			rc = vga_pci_cnattach(early_io_t,
			    early_mem_t, NULL, 0, dev, 0);
		}
#endif
		if (rc == 0)
			goto setup_kbd;
	}

	cn_tab = cp;

	/* no glass console... */
	return;

setup_kbd:

	/*
	 * Look for a suitable input device.
	 */

	rc = ENXIO;

#if NPCKBC > 0
	if (rc != 0 && early_io_t != NULL)
		rc = pckbc_cnattach(early_io_t, IO_KBD, KBCMDP, 0);
#endif
#if NUKBD > 0
	if (rc != 0)
		rc = ukbd_cnattach();
#endif

	cn_tab = cp;
}

void
wscnputc(dev_t dev, int i)
{
#if NWSDISPLAY > 0
	wsdisplay_cnputc(dev, i);
#endif
}

int
wscngetc(dev_t dev)
{
#if NPCKBD > 0 || NUKBD > 0
	int c;

	wskbd_cnpollc(dev, 1);
	c = wskbd_cngetc(dev);
	wskbd_cnpollc(dev, 0);

	return c;
#else
	for (;;) ;
#endif
}

void
wscnpollc(dev_t dev, int on)
{
#if NPCKBD > 0 || NUKBD > 0
	wskbd_cnpollc(dev, on);
#endif
}


code:
/*	$OpenBSD: yeeloong_machdep.c,v 1.24 2014/03/27 22:16:03 miod Exp $	*/

/*
 * Copyright (c) 2009, 2010 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.
 */

/*
 * eBenton EBT700 and Lemote {Fu,Lyn,Yee}loong specific code and
 * configuration data.
 * (this file probably ought to be named lemote_machdep.c by now)
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <machine/autoconf.h>
#include <machine/cpu.h>
#include <mips64/loongson2.h>
#include <mips64/mips_cpu.h>
#include <machine/pmon.h>

#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>

#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>

#include <dev/pci/glxreg.h>
#include <dev/pci/glxvar.h>

#include <loongson/dev/bonitoreg.h>
#include <loongson/dev/bonitovar.h>
#include <loongson/dev/bonito_irq.h>
#include <loongson/dev/kb3310var.h>

#include "com.h"
#include "ykbec.h"

#if NCOM > 0
#include <sys/termios.h>
#include <dev/ic/comvar.h>
extern struct mips_bus_space bonito_pci_io_space_tag;
#endif

void	 lemote_device_register(struct device *, void *);
void	 lemote_reset(void);

void	 ebenton_setup(void);

void	 fuloong_powerdown(void);
void	 fuloong_setup(void);

void	 yeeloong_powerdown(void);
void	 yeeloong_setup(void);

void	 lemote_pci_attach_hook(pci_chipset_tag_t);
int	 lemote_intr_map(int, int, int);

void	 lemote_isa_attach_hook(struct device *, struct device *,
	    struct isabus_attach_args *);
void	*lemote_isa_intr_establish(void *, int, int, int, int (*)(void *),
	    void *, char *);
void	 lemote_isa_intr_disestablish(void *, void *);

uint	 lemote_get_isa_imr(void);
uint	 lemote_get_isa_isr(void);
uint32_t lemote_isa_intr(uint32_t, struct trap_frame *);
extern void	(*cpu_setperf)(int);

const struct bonito_config lemote_bonito = {
	.bc_adbase = 11,

	.bc_gpioIE = LOONGSON_INTRMASK_GPIO,
	.bc_intEdge = LOONGSON_INTRMASK_PCI_SYSERR |
	    LOONGSON_INTRMASK_PCI_PARERR,
	.bc_intSteer = 0,
	.bc_intPol = LOONGSON_INTRMASK_DRAM_PARERR |
	    LOONGSON_INTRMASK_PCI_SYSERR | LOONGSON_INTRMASK_PCI_PARERR |
	    LOONGSON_INTRMASK_INT0 | LOONGSON_INTRMASK_INT1,

	.bc_attach_hook = lemote_pci_attach_hook,
	.bc_intr_map = lemote_intr_map
};

const struct legacy_io_range fuloong_legacy_ranges[] = {
	/* isa */
	{ IO_DMAPG + 4,	IO_DMAPG + 4 },
	/* mcclock */
	{ IO_RTC,	IO_RTC + 1 },
	/* pciide */
	{ 0x170,	0x170 + 7 },
	{ 0x1f0,	0x1f0 + 7 },
	{ 0x376,	0x376 },
	{ 0x3f6,	0x3f6 },
	/* com */
	{ IO_COM1,	IO_COM1 + 8 },		/* IR port */
	{ IO_COM2,	IO_COM2 + 8 },		/* serial port */

	{ 0 }
};

const struct legacy_io_range lynloong_legacy_ranges[] = {
	/* isa */
	{ IO_DMAPG + 4,	IO_DMAPG + 4 },
	/* mcclock */
	{ IO_RTC,	IO_RTC + 1 },
	/* pciide */
	{ 0x170,	0x170 + 7 },
	{ 0x1f0,	0x1f0 + 7 },
	{ 0x376,	0x376 },
	{ 0x3f6,	0x3f6 },
#if 0	/* no external connector */
	/* com */
	{ IO_COM2,	IO_COM2 + 8 },
#endif

	{ 0 }
};

const struct legacy_io_range yeeloong_legacy_ranges[] = {
	/* isa */
	{ IO_DMAPG + 4,	IO_DMAPG + 4 },
	/* pckbc */
	{ IO_KBD,	IO_KBD },
	{ IO_KBD + 4,	IO_KBD + 4 },
	/* mcclock */
	{ IO_RTC,	IO_RTC + 1 },
	/* pciide */
	{ 0x170,	0x170 + 7 },
	{ 0x1f0,	0x1f0 + 7 },
	{ 0x376,	0x376 },
	{ 0x3f6,	0x3f6 },
	/* kb3110b embedded controller */
	{ 0x381,	0x383 },

	{ 0 }
};

struct mips_isa_chipset lemote_isa_chipset = {
	.ic_v = NULL,

	.ic_attach_hook = lemote_isa_attach_hook,
	.ic_intr_establish = lemote_isa_intr_establish,
	.ic_intr_disestablish = lemote_isa_intr_disestablish
};

const struct platform fuloong_platform = {
	.system_type = LOONGSON_FULOONG,
	.vendor = "Lemote",
	.product = "Fuloong",

	.bonito_config = &lemote_bonito,
	.isa_chipset = &lemote_isa_chipset,
	.legacy_io_ranges = fuloong_legacy_ranges,

	.setup = fuloong_setup,
	.device_register = lemote_device_register,

	.powerdown = fuloong_powerdown,
	.reset = lemote_reset
};

const struct platform lynloong_platform = {
	.system_type = LOONGSON_LYNLOONG,
	.vendor = "Lemote",
	.product = "Lynloong",

	.bonito_config = &lemote_bonito,
	.isa_chipset = &lemote_isa_chipset,
	.legacy_io_ranges = lynloong_legacy_ranges,

	.setup = fuloong_setup,
	.device_register = lemote_device_register,

	.powerdown = fuloong_powerdown,
	.reset = lemote_reset
};

const struct platform yeeloong_platform = {
	.system_type = LOONGSON_YEELOONG,
	.vendor = "Lemote",
	.product = "Yeeloong",

	.bonito_config = &lemote_bonito,
	.isa_chipset = &lemote_isa_chipset,
	.legacy_io_ranges = yeeloong_legacy_ranges,

	.setup = yeeloong_setup,
	.device_register = lemote_device_register,

	.powerdown = yeeloong_powerdown,
	.reset = lemote_reset,
#if NYKBEC > 0
	.suspend = ykbec_suspend,
	.resume = ykbec_resume
#endif
};

/* eBenton EBT700 is similar to Lemote Yeeloong, except for a smaller screen */
const struct platform ebenton_platform = {
	.system_type = LOONGSON_EBT700,
	.vendor = "eBenton",
	.product = "EBT700",

	.bonito_config = &lemote_bonito,
	.isa_chipset = &lemote_isa_chipset,
	.legacy_io_ranges = yeeloong_legacy_ranges,

	.setup = ebenton_setup,
	.device_register = lemote_device_register,

	.powerdown = yeeloong_powerdown,
	.reset = lemote_reset,
#ifdef notyet
#if NYKBEC > 0
	.suspend = ykbec_suspend,
	.resume = ykbec_resume
#endif
#endif
};

/*
 * PCI model specific routines
 */

void
lemote_pci_attach_hook(pci_chipset_tag_t pc)
{
	pcireg_t id;
	pcitag_t tag;
	int dev;

	/*
	 * Check for an AMD CS5536 chip; if one is found, register
	 * the proper PCI configuration space hooks.
	 */

	for (dev = pci_bus_maxdevs(pc, 0); dev >= 0; dev--) {
		tag = pci_make_tag(pc, 0, dev, 0);
		id = pci_conf_read(pc, tag, PCI_ID_REG);
		if (id == PCI_ID_CODE(PCI_VENDOR_AMD,
		    PCI_PRODUCT_AMD_CS5536_PCISB)) {
			glx_init(pc, tag, dev);
			break;
		}
	}
}

int
lemote_intr_map(int dev, int fn, int pin)
{
	switch (dev) {
	/* onboard devices, only pin A is wired */
	case 6:
	case 7:
	case 8:
	case 9:
		if (pin == PCI_INTERRUPT_PIN_A)
			return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
			    (dev - 6));
		break;
	/* PCI slot */
	case 10:
		return BONITO_DIRECT_IRQ(LOONGSON_INTR_PCIA +
		    (pin - PCI_INTERRUPT_PIN_A));
	/* Geode chip */
	case 14:
		switch (fn) {
		case 1:	/* Flash */
			return BONITO_ISA_IRQ(6);
		case 3:	/* AC97 */
			return BONITO_ISA_IRQ(9);
		case 4:	/* OHCI */
		case 5:	/* EHCI */
			return BONITO_ISA_IRQ(11);
		}
		break;
	default:
		break;
	}

	return -1;
}

/*
 * ISA model specific routines
 */

void
lemote_isa_attach_hook(struct device *parent, struct device *self,
    struct isabus_attach_args *iba)
{
	set_intr(INTPRI_ISA, CR_INT_0, lemote_isa_intr);

	/* disable all isa interrupt sources */
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1) = 0xff;
	REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 2) = 0xff;

	loongson_generic_isa_attach_hook(parent, self, iba);
}

void *
lemote_isa_intr_establish(void *v, int irq, int type, int level,
    int (*handler)(void *), void *arg, char *name)
{
	return bonito_intr_establish(BONITO_ISA_IRQ(irq), type, level,
	    handler, arg, name);
}

void
lemote_isa_intr_disestablish(void *v, void *ih)
{
	bonito_intr_disestablish(ih);
}

/*
 * Legacy (ISA) interrupt handling
 */

/*
 * Process legacy interrupts.
 *
 * XXX On 2F, ISA interrupts only occur on LOONGSON_INTR_INT0, but since
 * XXX the other LOONGSON_INTR_INT# are unmaskable, bad things will happen
 * XXX if they ever are triggered...
 */
uint32_t
lemote_isa_intr(uint32_t hwpend, struct trap_frame *frame)
{
	uint64_t imr, isr, mask;
	int bit;
	struct intrhand *ih;
	int rc;

	isr = lemote_get_isa_isr();
	imr = lemote_get_isa_imr();

	isr &= imr;
	isr &= ~(1 << 2);	/* cascade */
#ifdef DEBUG
	printf("isa interrupt: imr %04x isr %04x\n", imr, isr);
#endif
	if (isr == 0)
		return 0;	/* not for us */

	/*
	 * Mask all pending interrupts.
	 */

	loongson_set_isa_imr(imr & ~isr);

	/*
	 * If interrupts are spl-masked, mask them and wait for splx()
	 * to reenable them when necessary.
	 */
	if ((mask = isr & (BONITO_ISA_MASK(bonito_imask[frame->ipl]))) != 0) {
		isr &= ~mask;
		imr &= ~mask;
	}

	/*
	 * Now process allowed interrupts.
	 */
	if (isr != 0) {
		int lvl, bitno, ret;
		uint64_t tmpisr;

		/* Service higher level interrupts first */
		bit = BONITO_NISA - 1;
		for (lvl = IPL_HIGH - 1; lvl != IPL_NONE; lvl--) {
			tmpisr = isr & BONITO_ISA_MASK(bonito_imask[lvl] ^
			    bonito_imask[lvl - 1]);
			if (tmpisr == 0)
				continue;
			for (bitno = bit, mask = 1UL << bitno; mask != 0;
			    bitno--, mask >>= 1) {
				if ((tmpisr & mask) == 0)
					continue;

				rc = 0;
				for (ih = bonito_intrhand[BONITO_ISA_IRQ(bitno)];
				    ih != NULL; ih = ih->ih_next) {
					void *arg;

					splraise(ih->ih_level);
					if (ih->ih_arg != NULL)
						arg = ih->ih_arg;
					else
						/* clock interrupt */
						arg = frame;
					ret = (*ih->ih_fun)(arg);
					if (ret) {
						rc = 1;
						ih->ih_count.ec_count++;
					}
					__asm__ (".set noreorder\n");
					curcpu()->ci_ipl = frame->ipl;
					mips_sync();
					__asm__ (".set reorder\n");
					if (ret == 1)
						break;
				}
				if (rc == 0)
					printf("spurious isa interrupt %d\n",
					    bitno);

				loongson_isa_specific_eoi(bitno);

				if ((isr ^= mask) == 0)
					goto done;
				if ((tmpisr ^= mask) == 0)
					break;
			}
		}
done:

		/*
		 * Reenable interrupts which have been serviced.
		 */
		loongson_set_isa_imr(imr);
	}

	return hwpend;
}

uint
lemote_get_isa_imr()
{
	uint imr1, imr2;

	imr1 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU1 + 1);
	imr1 &= ~(1 << 2);	/* hide cascade */
	imr2 = 0xff & ~REGVAL8(BONITO_PCIIO_BASE + IO_ICU2 + 1);

	return (imr2 << 8) | imr1;
}

uint
lemote_get_isa_isr()
{
	uint isr1, isr2;

	isr1 = 0xff & REGVAL8(BONITO_PCIIO_BASE + IO_ICU1);
	isr2 = 0xff & REGVAL8(BONITO_PCIIO_BASE + IO_ICU2);

	return (isr2 << 8) | isr1;
}

/*
 * Other model specific routines
 */

void
fuloong_powerdown()
{
	vaddr_t gpiobase;

	gpiobase = BONITO_PCIIO_BASE + (rdmsr(DIVIL_LBAR_GPIO) & 0xff00);
	/* enable GPIO 13 */
	REGVAL(gpiobase + GPIOL_OUT_EN) = GPIO_ATOMIC_VALUE(13, 1);
	/* set GPIO13 value to zero */
	REGVAL(gpiobase + GPIOL_OUT_VAL) = GPIO_ATOMIC_VALUE(13, 0);
}

void
yeeloong_powerdown()
{
	REGVAL(BONITO_GPIODATA) &= ~0x00000001;
	REGVAL(BONITO_GPIOIE) &= ~0x00000001;
}

void
lemote_reset()
{
	cpu_setperf(100);
	wrmsr(GLCP_SYS_RST, rdmsr(GLCP_SYS_RST) | 1);
}

void
fuloong_setup(void)
{
#if NCOM > 0
	const char *envvar;
	int serial;

	envvar = pmon_getenv("nokbd");
	serial = envvar != NULL;
	envvar = pmon_getenv("novga");
	serial = serial && envvar != NULL;

	if (serial) {
                comconsiot = &bonito_pci_io_space_tag;
                comconsaddr = 0x2f8;
                comconsrate = 115200; /* default PMON console speed */
		comconscflag = (TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) |
		    CS8 | CLOCAL; /* 8N1 */
	}
#endif

	cpu_setperf = loongson2f_setperf;

	bonito_early_setup();
}

void
yeeloong_setup(void)
{
	cpu_setperf = loongson2f_setperf;

	bonito_early_setup();
}

void
ebenton_setup(void)
{
	bonito_early_setup();
}

void
lemote_device_register(struct device *dev, void *aux)
{
	const char *drvrname = dev->dv_cfdata->cf_driver->cd_name;
	const char *name = dev->dv_xname;

	if (dev->dv_class != bootdev_class)
		return;

	/*
	 * The device numbering must match. There's no way
	 * pmon tells us more info. Depending on the usb slot
	 * and hubs used you may be lucky. Also, assume umass/sd for usb
	 * attached devices.
	 */
	switch (bootdev_class) {
	case DV_DISK:
		if (strcmp(drvrname, "wd") == 0 && strcmp(name, bootdev) == 0)
			bootdv = dev;
		else {
			/* XXX this really only works safely for usb0... */
		    	if ((strcmp(drvrname, "sd") == 0 ||
			    strcmp(drvrname, "cd") == 0) &&
			    strncmp(bootdev, "usb", 3) == 0 &&
			    strcmp(name + 2, bootdev + 3) == 0)
				bootdv = dev;
		}
		break;
	case DV_IFNET:
		/*
		 * This relies on the onboard Ethernet interface being
		 * attached before any other (usb) interface.
		 */
		bootdv = dev;
		break;
	default:
		break;
	}
}


code:
/Makefile/1.2/Wed Feb 17 19:56:43 2010//TOPENBSD_5_8_BASE
/Makefile.inc/1.5/Sun Jun  2 19:52:36 2013//TOPENBSD_5_8_BASE
D/boot////
D/libsa////
D/mbr////

path: sys/arch/loongson/stand/CVS/Entries


code: src/sys/arch/loongson/stand

path: sys/arch/loongson/stand/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.2 2010/02/17 19:56:43 otto Exp $

.if ${MACHINE} == "loongson"
SUBDIR+=	libsa
.endif
SUBDIR+=	boot mbr

.include <bsd.subdir.mk>

path: sys/arch/loongson/stand/Makefile


code:
#	$OpenBSD: Makefile.inc,v 1.5 2013/06/02 19:52:36 jasper Exp $

BINDIR=		/usr/mdec

STANDALONE?=	-D_STANDALONE

.if ${MACHINE} == "loongson"
CPPFLAGS+=	${STANDALONE}
CPPFLAGS+=	-I.
CFLAGS+=	-fno-stack-protector -Wall
CFLAGS+=	-fno-builtin-vprintf -fno-builtin-printf -fno-builtin-putchar
# Silence warnings
CFLAGS+=	-fno-builtin-snprintf
CFLAGS+=	-fno-builtin-memcpy
CFLAGS+=	-fno-builtin-memcmp
CFLAGS+=	-fno-builtin-memset
CFLAGS+=	-fno-builtin-strncpy
CFLAGS+=	-fno-builtin-strncmp
CFLAGS+=	-fno-builtin-exit
CFLAGS+=	-Wa,-mfix-loongson2f-btb
SAABI=		-mips3 -mno-abicalls -G 0 -fno-pic -fno-common
AS?=		as
LD?=		ld
.endif

### Figure out what to use for libsa
LIBSADIR?=               ${.CURDIR}/../libsa

.if exists(${LIBSADIR}/${__objdir})
LIBSAOBJDIR=            ${LIBSADIR}/${__objdir}
.else
LIBSAOBJDIR=            ${LIBSADIR}
.endif

LIBSA=                  ${LIBSAOBJDIR}/libsa.a

### Figure out what to use for libz
LIBZDIR?=                ${.CURDIR}/../libz

.if exists(${LIBZDIR}/${__objdir})
LIBZOBJDIR=             ${LIBZDIR}/${__objdir}
.else
LIBZOBJDIR=             ${LIBZDIR}
.endif

LIBZ=                   ${LIBZOBJDIR}/libz.a


path: sys/arch/loongson/stand/boot/CVS/Tag


code:
#	$OpenBSD: Makefile,v 1.4 2012/11/04 16:30:44 matthieu Exp $

NOMAN=
#MAN=		boot.8
#MLINKS=	boot.8 boot.conf.5
.if ${MACHINE} == "loongson"
PROG=		boot
.include	"${.CURDIR}/Makefile.inc"
.else
NOPROG=
.endif
CFLAGS+=-fno-pie
AFLAGS+=-fno-pie
LDFLAGS+=-nopie

.include <bsd.prog.mk>

path: sys/arch/loongson/stand/boot/Makefile


code:
#	$OpenBSD: Makefile.inc,v 1.4 2014/07/12 23:34:54 jasper Exp $

NOMAN=
S=		${.CURDIR}/../../../..
BOOTDIR=	${S}/arch/loongson/stand/boot

CPPFLAGS+=	${SAABI} -mno-abicalls -D_NO_ABICALLS -DCONSPEED=9600 \
		-nostdinc -D__loongson__ \
		-I${S} -I${S}/lib/libsa \
		-I${.OBJDIR} -I${BOOTDIR}

LDSCRIPT=	${.CURDIR}/ld.script
LDFLAGS+=	${SALDFLAGS} -T ${LDSCRIPT} -e __start

AFLAGS+=	${SAABI}

.PATH:		${BOOTDIR}
SRCS=		start.S
SRCS+=		conf.c cons.c dev.c devopen.c exec.c machdep.c rd.c
.PATH:		${S}/arch/loongson/loongson
SRCS+=		pmon.c pmon32.S

#### MI boot code
.PATH:		${S}/stand/boot
SRCS+=		boot.c cmd.c vars.c

#### libkern
.PATH:		${S}/lib/libkern/arch/mips64 ${S}/lib/libkern
SRCS+=		strlcat.c strlcpy.c strlen.c
SRCS+=		udivdi3.c qdivrem.c

.if !make(obj)
.BEGIN:
	@([ -h machine ] || ln -s ${.CURDIR}/../../include machine)
	@([ -h mips64 ] || ln -s ${.CURDIR}/../../../mips64/include mips64)
CLEANFILES+= machine mips64
.endif

${PROG}: ${OBJS} ${LIBSA}
	${LD} ${LDFLAGS} -o ${PROG} ${OBJS} ${LIBSA}


code:
/*	$OpenBSD: conf.c,v 1.6 2013/12/28 02:53:04 deraadt Exp $	*/

/*
 * Copyright (c) 1982, 1986, 1990, 1993
 *	The Regents of the University of California.  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.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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.
 *
 *	@(#)conf.c	8.1 (Berkeley) 6/10/93
 */

#include <sys/param.h>

#include <dev/cons.h>

#include "libsa.h"
#include <lib/libsa/ufs.h>
#include <lib/libsa/cd9660.h>

const char version[] = "0.4";
#if 0	/* network code not compiled in */
int	debug = 0;
#endif

/*
 * Device configuration
 */
struct devsw devsw[] = {
	/* initrd */
	{ "rd",		rd_iostrategy, rd_ioopen, rd_ioclose, noioctl },
	/* ATA storage device */
	{ "wd",		pmon_iostrategy, pmon_ioopen, pmon_ioclose, noioctl }
};
int ndevs = nitems(devsw);

/*
 * Filesystem configuration
 */
struct fs_ops file_system[] = {
	/* initrd ``filesystem'' */
	{	rdfs_open,	rdfs_close,	rdfs_read,	rdfs_write,
		rdfs_seek,	rdfs_stat,	rdfs_readdir	},
	/* ufs filesystem */
	{	ufs_open,	ufs_close,	ufs_read,	ufs_write,
		ufs_seek,	ufs_stat,	ufs_readdir	},
	/* cd9660 filesystem - in case a cd image is dd'ed on non USB media */
	{	cd9660_open,	cd9660_close,	cd9660_read,	cd9660_write,
		cd9660_seek,	cd9660_stat,	cd9660_readdir	}
};
int nfsys = nitems(file_system);

/*
 * Console configuration
 */
struct consdev constab[] = {
	{ pmon_cnprobe, pmon_cninit, pmon_cngetc, pmon_cnputc },
	{ NULL }
};
struct consdev *cn_tab;


code:
/*	$OpenBSD: cons.c,v 1.2 2010/02/16 21:28:39 miod Exp $	*/

/*
 * Copyright (c) 2010 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.
 */

#include <lib/libkern/libkern.h>
#include "libsa.h"
#include <dev/cons.h>
#include <machine/cpu.h>
#include <machine/pmon.h>

/*
 * PMON console
 */

void
pmon_cnprobe(struct consdev *cn)
{
	cn->cn_pri = CN_HIGHPRI;
}

void
pmon_cninit(struct consdev *cn)
{
}

int
pmon_cngetc(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.
	 *
	 * Note that one could theoretically use pmon_read(STDIN, &c, 1)
	 * but the value of STDIN within PMON is not a constant and there
	 * does not seem to be a way of letting us know which value to use.
	 */
	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 */
			strlcpy(buf, "\n", sizeof buf);
		} else {
			/* put back the \n sign */
			buf[strlen(buf)] = '\n';
		}
	}

	c = (int)*bufpos;
	if ((dev & 0x80) == 0) {
		bufpos++;
		if (bufpos - buf > PMON_MAXLN) {
			bufpos = buf;
			*bufpos = '\0';
		}
	}

	return c;
}

void
pmon_cnputc(dev_t dev, int c)
{
	if (c == '\n')
		pmon_printf("\n");
	else
		pmon_printf("%c", c);
}


code:
/*	$OpenBSD: dev.c,v 1.7 2014/07/12 21:03:38 tedu Exp $	*/

/*
 * Copyright (c) 2010 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 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Manuel Bouyer.
 *
 * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <sys/param.h>
#include "libsa.h"
#include <sys/disklabel.h>
#include <machine/cpu.h>
#include <machine/pmon.h>

/*
 * PMON I/O
 */

char	pmon_bootdev[1 + 256];

struct pmon_iodata {
	int			fd;
	struct disklabel	label;
	off_t			partoff;
	off_t			curpos;
};

int	pmon_getdisklabel(struct pmon_iodata *pi);

int
pmon_iostrategy(void *f, int rw, daddr32_t dblk, size_t size, void *buf,
    size_t *rsize)
{
	struct pmon_iodata *pi = (struct pmon_iodata *)f;
	off_t offs, pos;
	int rc;

	*rsize = 0;
	if (size == 0)
		return 0;

	if (rw != F_READ)
		return EOPNOTSUPP;

	offs = ((daddr_t)dblk + pi->partoff) * DEV_BSIZE;
	if (offs != pi->curpos) {
		pos = pmon_lseek(pi->fd, offs, 0 /* SEEK_SET */);
		if (pos != offs)
			return EINVAL;
	}

	/* note this expects size to fit in 32 bits */
	rc = pmon_read(pi->fd, buf, size);
	if (rc >= 0) {
		pi->curpos += rc;
		*rsize = rc;
	} else
		*rsize = 0;

	if (rc != size)
		return EIO;
	return 0;
}

int
pmon_ioopen(struct open_file *f, ...)
{
	struct pmon_iodata *pi;
	int rc;
	va_list ap;
	uint unit, part;

	pi = alloc(sizeof *pi);
	if (pi == NULL)
		return ENOMEM;
	bzero(pi, sizeof *pi);
	f->f_devdata = pi;

	va_start(ap, f);
	unit = va_arg(ap, uint);
	part = va_arg(ap, uint);
	va_end(ap);

	/*
	 * Open the raw device through PMON.
	 */

	snprintf(pmon_bootdev, sizeof pmon_bootdev, "/dev/disk/%s%d",
	    f->f_dev->dv_name, unit);
	rc = pmon_open(pmon_bootdev, 0 /* O_RDONLY */);
	if (rc < 0)
		return ENXIO;

	pi->fd = rc;

	/*
	 * Read disklabel.
	 */

	if (pmon_getdisklabel(pi) != 0) {
		pmon_ioclose(f);
		return ENXIO;
	}

	if (part >= pi->label.d_npartitions) {
		pmon_ioclose(f);
		return EPART;
	}

	pi->partoff = DL_GETPOFFSET(&pi->label.d_partitions[part]);
	pi->curpos = 0;

	return 0;
}

int
pmon_ioclose(struct open_file *f)
{
	struct pmon_iodata *pi;
	int rc;

	if (f->f_devdata != NULL) {
		pi = (struct pmon_iodata *)f->f_devdata;
		rc = pmon_close(pi->fd);
		free(pi, sizeof *pi);
		f->f_devdata = NULL;
	} else
		rc = 0;

	return rc;
}

/*
 * Read disk label from the device.
 */
int
pmon_getdisklabel(struct pmon_iodata *pi)
{
	char *msg;
	int sector;
	size_t rsize;
	struct disklabel *lp = &pi->label;
	char buf[DEV_BSIZE];

	bzero(lp, sizeof *lp);

	/*
	 * Find OpenBSD Partition in DOS partition table.
	 */
	sector = 0;
	if (pmon_iostrategy(pi, F_READ, DOSBBSECTOR, DEV_BSIZE, buf, &rsize))
		return ENXIO;

	if (*(u_int16_t *)&buf[DOSMBR_SIGNATURE_OFF] == DOSMBR_SIGNATURE) {
		int i;
		struct dos_partition *dp = (struct dos_partition *)buf;

		/*
		 * Lookup OpenBSD slice. If there is none, go ahead
		 * and try to read the disklabel off sector #0.
		 */
		memcpy(dp, &buf[DOSPARTOFF], NDOSPART * sizeof(*dp));
		for (i = 0; i < NDOSPART; i++) {
			if (dp[i].dp_typ == DOSPTYP_OPENBSD) {
				sector = letoh32(dp[i].dp_start);
				break;
			}
		}
	}

	if (pmon_iostrategy(pi, F_READ, sector + LABELSECTOR, DEV_BSIZE,
				buf, &rsize))
		return ENXIO;

	if ((msg = getdisklabel(buf + LABELOFFSET, lp))) {
		printf("getdisklabel: %s\n", msg);
		return ENXIO;
	}

	return 0;
}


code:
/*	$OpenBSD: devopen.c,v 1.1 2010/02/14 22:39:33 miod Exp $	*/

/*-
 * Copyright (c) 2003 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Rolf Grossmann.
 *
 * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 "libsa.h"

#define MAXDEVNAME      16

/*
 * Parse a device spec.
 *
 * [A-Za-z]*[0-9]*[A-Za-z]:file
 *    dev   uint    part
 */
int
devparse(const char *fname, int *dev, int *unit, int *part, const char **file)
{
	const char *s;

	*unit = 0;	/* default to wd0a */
	*part = 0;
	*dev  = 0;

	s = strchr(fname, ':');
	if (s != NULL) {
		int devlen;
		int i, u, p = 0;
		struct devsw *dp;
		char devname[MAXDEVNAME];

		devlen = s - fname;
		if (devlen > MAXDEVNAME)
			return (EINVAL);

		/* extract device name */
		for (i = 0; isalpha(fname[i]) && (i < devlen); i++)
			devname[i] = fname[i];
		devname[i] = 0;

		if (!isdigit(fname[i]))
			return (EUNIT);

		/* device number */
		for (u = 0; isdigit(fname[i]) && (i < devlen); i++)
			u = u * 10 + (fname[i] - '0');

		if (!isalpha(fname[i]))
			return (EPART);

		/* partition number */
		if (i < devlen)
			p = fname[i++] - 'a';

		if (i != devlen)
			return (ENXIO);

		/* check device name */
		for (dp = devsw, i = 0; i < ndevs; dp++, i++) {
			if (dp->dv_name && !strcmp(devname, dp->dv_name))
				break;
		}

		if (i >= ndevs)
			return (ENXIO);

		*unit = u;
		*part = p;
		*dev  = i;
		fname = ++s;
	}

	*file = fname;

	return (0);
}

int
devopen(struct open_file *f, const char *fname, char **file)
{
	struct devsw *dp;
	int dev, unit, part, error;

	error = devparse(fname, &dev, &unit, &part, (const char **)file);
	if (error)
		return (error);

	dp = &devsw[dev];
	if ((void *)dp->dv_open == (void *)nodev)
		return (ENXIO);

	f->f_dev = dp;

	return (*dp->dv_open)(f, unit, part);
}


code:
/*	$OpenBSD: exec.c,v 1.3 2014/11/18 20:51:01 krw Exp $	*/

/*
 * Copyright (c) 2010 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.
 */

#include <sys/param.h>
#include <sys/reboot.h>
#include <machine/cpu.h>
#include <machine/pmon.h>
#include "libsa.h"
#include <lib/libsa/loadfile.h>

typedef void (*program)(int32_t, int32_t, int32_t *, int32_t, uint64_t *);

#define	PTR_TO_CKSEG1(ptr)	(int32_t)(CKSEG1_BASE | (uint64_t)(ptr))

void
run_loadfile(u_long *marks, int howto)
{
	int32_t newargc;
	int32_t *newargv;
	char kernelflags[8];
	char *c;
	const char *arg;

	/*
	 * Build a new commandline:
	 * boot <device kernel is loaded from> -<kernel options>
	 */

	newargc = howto == 0 ? 2 : 3;
	newargv = alloc(newargc * sizeof(int32_t));
	if (newargv == NULL)
		panic("out of memory");

	arg = "boot";	/* kernel needs this. */
	newargv[0] = PTR_TO_CKSEG1(arg);
	newargv[1] = PTR_TO_CKSEG1(&pmon_bootdev);
	if (howto != 0) {
		c = kernelflags;
		*c++ = '-';
		if (howto & RB_ASKNAME)
			*c++ = 'a';
		if (howto & RB_CONFIG)
			*c++ = 'c';
		if (howto & RB_KDB)
			*c++ = 'd';
		if (howto & RB_SINGLE)
			*c++ = 's';
		*c = '\0';
		newargv[2] = PTR_TO_CKSEG1(&kernelflags);
	}

	pmon_cacheflush();

	(*(program)(marks[MARK_ENTRY]))(newargc, PTR_TO_CKSEG1(newargv),
	    pmon_envp, pmon_callvec,
	    (uint64_t *)PHYS_TO_CKSEG0(marks[MARK_END]));

	rd_invalidate();
	_rtt();
}


code:
OUTPUT_FORMAT("elf64-tradlittlemips")
OUTPUT_ARCH(mips)
ENTRY(__start)

SECTIONS
{
	/*
	 * Load at 30MB; should be more than enough to be able to load the
	 * kernel image without overwriting ourselves.
	 */
	. = 0xffffffff81e20000 + SIZEOF_HEADERS;
	.text :		{ *(.text .text.* .gnu.linkonce.t.*) }
	PROVIDE (etext = .);
	.rodata :	{ *(.rodata .rodata.* .gnu.linkonce.r.*) }
	_gp = ALIGN(16) + 0x7ff0;
	.data :		{ *(.data .data.* .gnu.linkonce.d.*) }
	PROVIDE (edata = .);
	.sbss :		{ *(.sbss .sbss.* .gnu.linkonce.sb.* .scommon) }
	.bss :		{ *(.bss .bss.* .gnu.linkonce.b.* COMMON) }
	PROVIDE (_end = .);
	PROVIDE (end = .);
	/DISCARD/ :
	{
		*(.pdr)
		*(.mdebug.abi64)
		*(.MIPS.options)
	}
}


code:
/*	$OpenBSD: libsa.h,v 1.5 2011/03/13 00:13:53 deraadt Exp $	*/

/*
 * Copyright (c) 2010 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.
 */

#include <lib/libsa/stand.h>

#define	DEFAULT_KERNEL_ADDRESS	0

/* where the initrd is loaded */
#define	INITRD_BASE	PHYS_TO_CKSEG0(0x04000000)

/*
 * MD interfaces for MI boot(9)
 */
void	devboot(dev_t, char *);
void	machdep(void);
void	run_loadfile(u_long *, int);

/*
 * PMON console
 */
void	pmon_cnprobe(struct consdev *);
void	pmon_cninit(struct consdev *);
int	pmon_cngetc(dev_t);
void	pmon_cnputc(dev_t, int);

/*
 * PMON I/O
 */
int	pmon_iostrategy(void *, int, daddr32_t, size_t, void *, size_t *);
int	pmon_ioopen(struct open_file *, ...);
int	pmon_ioclose(struct open_file *);

/*
 * INITRD I/O
 */
int	rd_iostrategy(void *, int, daddr32_t, size_t, void *, size_t *);
int	rd_ioopen(struct open_file *, ...);
int	rd_ioclose(struct open_file *);
int	rd_isvalid(void);
void	rd_invalidate(void);

/*
 * INITRD ``filesystem''
 */
int	rdfs_open(char *path, struct open_file *f);
int	rdfs_close(struct open_file *f);
int	rdfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
int	rdfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
off_t	rdfs_seek(struct open_file *f, off_t offset, int where);
int	rdfs_stat(struct open_file *f, struct stat *sb);
int	rdfs_readdir(struct open_file *f, char *name);

extern int pmon_argc;
extern int32_t *pmon_argv;
extern int32_t *pmon_envp;
extern int32_t pmon_callvec;

extern char pmon_bootdev[];

extern char *kernelfile;


code:
/*	$OpenBSD: machdep.c,v 1.8 2014/07/13 09:26:08 jasper Exp $	*/

/*
 * Copyright (c) 2010 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) 1998-2004 Michael Shalayeff
 * 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 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 OR HIS RELATIVES 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 MIND, 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 <lib/libkern/libkern.h>
#include "libsa.h"
#include <machine/cpu.h>
#include <machine/pmon.h>
#include <stand/boot/cmd.h>

void	gdium_abort(void);
int	is_gdium;
int	boot_rd;

extern int bootprompt;

/*
 * Console
 */

int
cnspeed(dev_t dev, int sp)
{
	return CONSPEED;
}

char *
ttyname(int fd)
{
	return "pmon console";
}

dev_t
ttydev(char *name)
{
	/* we do not support any other console than pmon */
	return NODEV;
}

/*
 * Configuration and device path aerobics
 */

/*
 * Return the default boot device.
 */
void
devboot(dev_t dev, char *path)
{
	const char *bootpath = NULL;
	size_t bootpathlen = 0;	/* gcc -Wall */
	const char *tmp;
	int i;

	/*
	 * If we are booting the initrd image, things are easy...
	 */

	if (dev != 0) {
		strlcpy(path, "rd0a", BOOTDEVLEN);
		return;
	}

	/*
	 * First, try to figure where we have been loaded from; we'll assume
	 * the default device to load the kernel from is the same.
	 *
	 * We may have been loaded in three different ways:
	 * - automatic load from `al' environment variable (similar to a
	 *   `load' and `go' sequence).
	 * - manual `boot' command, with path on the commandline.
	 * - manual `load' and `go' commands, with no path on the commandline.
	 */

	if (pmon_argc > 0) {
		tmp = (const char *)pmon_getarg(0);
		if (tmp[0] != 'g') {
			/* manual load */
			for (i = 1; i < pmon_argc; i++) {
				tmp = (const char *)pmon_getarg(i);
				if (tmp[0] != '-') {
					bootpath = tmp;
					break;
				}
			}
		} else {
			/* possible automatic load */
			bootpath = pmon_getenv("al");
		}
	}

	/*
	 * If the bootblocks have been loaded from the network,
	 * use the default disk.
	 */

	if (bootpath != NULL && strncmp(bootpath, "tftp://", 7) == 0)
		bootpath = NULL;

	/*
	 * Now extract the device name from the bootpath.
	 */

	if (bootpath != NULL) {
		tmp = strchr(bootpath, '@');
		if (tmp == NULL) {
			bootpath = NULL;
		} else {
			bootpath = tmp + 1;
			tmp = strchr(bootpath, '/');
			if (tmp == NULL) {
				bootpath = NULL;
			} else {
				bootpathlen = tmp - bootpath;
			}
		}
	}

	if (bootpath != NULL && bootpathlen >= 3) {
		if (bootpathlen >= BOOTDEVLEN)
			bootpathlen = BOOTDEVLEN - 1;
		strncpy(path, bootpath, bootpathlen);
		path[bootpathlen] = '\0';
		/* only add a partition letter if there is none */
		if (bootpath[bootpathlen - 1] >= '0' &&
		    bootpath[bootpathlen - 1] <= '9')
			strlcat(path, "a", BOOTDEVLEN);
	} else {
		strlcpy(path, "wd0a", BOOTDEVLEN);
	}
}

/*
 * Ugly (lack of) clock routines
 */

time_t
getsecs()
{
	return 0;
}

/*
 * Initialization
 */

void
machdep()
{
	const char *envvar;

	/*
	 * Since we can't have non-blocking input, we will try to
	 * autoload the kernel pointed to by the `bsd' environment
	 * variable, and fallback to interactive mode if the variable
	 * is empty or the load fails.
	 */

	if (boot_rd == 0) {
		envvar = pmon_getenv("bsd");
		if (envvar != NULL) {
			bootprompt = 0;
			kernelfile = (char *)envvar;
		} else {
			if (is_gdium)
				gdium_abort();
		}
	}
}

int
main()
{
	const char *envvar;

	cninit();

	/*
	 * Figure out whether we are running on a Gdium system, which
	 * has an horribly castrated PMON. If we do, the best we can do
	 * is boot an initrd image.
	 */
	envvar = pmon_getenv("Version");
	if (envvar != NULL && strncmp(envvar, "Gdium", 5) == 0)
		is_gdium = 1;

	/*
	 * Check if we have a valid initrd loaded.
	 */

	envvar = pmon_getenv("rd");
	if (envvar != NULL && *envvar != '\0')
		boot_rd = rd_isvalid();

	if (boot_rd != 0)
		bootprompt = 0;

	boot(boot_rd);
	return 0;
}

void
gdium_abort()
{
	/* Here's a nickel, kid.  Get yourself a better firmware */
	printf("\n\nSorry, OpenBSD boot blocks do not work on Gdium, "
	    "because of dire firmware limitations.\n"
	    "Also, the firmware has reset the USB controller so you "
	    "will need to power cycle.\n"
	    "We would apologize for this inconvenience, but we have "
	    "no control about the firmware of your machine.\n\n");
	rd_invalidate();
	_rtt();
}


code:
/*	$OpenBSD: rd.c,v 1.4 2013/03/24 19:20:35 deraadt Exp $	*/

/*
 * Copyright (c) 2010 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.
 */

#include <sys/param.h>
#include "libsa.h"
#include <machine/cpu.h>
#include <sys/exec_elf.h>

static	off_t rdoffs;

/*
 * INITRD I/O
 */

int
rd_iostrategy(void *f, int rw, daddr32_t dblk, size_t size, void *buf,
    size_t *rsize)
{
	/* never invoked directly */
	return ENXIO;
}

int
rd_ioopen(struct open_file *f, ...)
{
	return 0;
}

int
rd_ioclose(struct open_file *f)
{
	return 0;
}

int
rd_isvalid()
{
	Elf64_Ehdr *elf64 = (Elf64_Ehdr *)INITRD_BASE;

	if (memcmp(elf64->e_ident, ELFMAG, SELFMAG) != 0 ||
	    elf64->e_ident[EI_CLASS] != ELFCLASS64 ||
	    elf64->e_ident[EI_DATA] != ELFDATA2LSB ||
	    elf64->e_type != ET_EXEC || elf64->e_machine != EM_MIPS)
		return 0;

	return 1;
}

void
rd_invalidate()
{
	bzero((void *)INITRD_BASE, sizeof(Elf64_Ehdr));
}

/*
 * INITRD filesystem
 */
int
rdfs_open(char *path, struct open_file *f)
{
	if (f->f_dev->dv_open == rd_ioopen) {
		if (strcmp(path, kernelfile) == 0) {
			rdoffs = 0;
			return 0;
		} else
			return ENOENT;
	}

	return EINVAL;
}

int
rdfs_close(struct open_file *f)
{
	return 0;
}

int
rdfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
{
	if (size != 0) {
		bcopy((void *)(INITRD_BASE + rdoffs), buf, size);
		rdoffs += size;
	}
	*resid = 0;

	return 0;
}

int
rdfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
{
	return EROFS;
}

off_t
rdfs_seek(struct open_file *f, off_t offset, int whence)
{
	switch (whence) {
	case 0:	/* SEEK_SET */
		rdoffs = offset;
		break;
	case 1: /* SEEK_CUR */
		rdoffs += offset;
		break;
	default:
		errno = EIO;
		return -1;
	}

	return rdoffs;
}

int
rdfs_stat(struct open_file *f, struct stat *sb)
{
	return EIO;
}

#ifndef NO_READDIR
int
rdfs_readdir(struct open_file *f, char *path)
{
	return EIO;
}
#endif


code:
/*	$OpenBSD: start.S,v 1.1 2010/02/14 22:39:33 miod Exp $	*/

/*
 * Copyright (c) 2010 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.
 */

#include <machine/asm.h>
#include <machine/regdef.h>

	.set	noreorder
	.set	mips3

	.data
pmon_ra:
	.dword	0
pmon_sp:
	.dword	0

	.text

	.globl	__start
	.ent	__start, 0
__start:
	LA	t0, __start - FRAMESZ(CF_SZ)
	LA	gp, _gp
	PTR_S	ra, pmon_ra		# save pmon return address
	PTR_S	sp, pmon_sp		# and stack
	move	sp, t0
	jal	pmon_init		# pmon_init(argc, argv, envp, callvec)
	nop
	jal	main
	nop
	/* FALLTHROUGH */
	.end	__start

	.globl	_rtt
	.ent	_rtt,0
_rtt:
	PTR_L	ra, pmon_ra
	PTR_L	sp, pmon_sp
	jr	ra
	nop
	.end	_rtt


code:
/Makefile/1.6/Sun Jul 13 09:26:08 2014//TOPENBSD_5_8_BASE
D


code: src/sys/arch/loongson/stand/libsa


path: sys/arch/loongson/stand/libsa/CVS/Tag