code:
/*
 * Copyright (c) 2013 Joel Sing <jsing@openbsd.org>
 *
 * 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/param.h>
#include <machine/asm.h>
#include <machine/psl.h>
#include <machine/specialreg.h>

/*
 * Random data is xored into the buffer in 4 byte blocks. If the buffer size
 * is not a multiple of 4, the remaining bytes will be left untouched.
 */
ENTRY(mdrandom)
	pushal

	// See if we have CPU identification.
	pushfl
	popl	%eax
	movl	%eax, %ecx
	orl	$PSL_ID, %eax
	pushl	%eax
	popfl
	pushfl
	popl	%eax
	pushl	%ecx
	popfl
	andl	$PSL_ID, %eax
	jz	done

	// CPUID leaf = 0, subleaf = 0
	movl	$0, %eax
	movl	$0, %ecx
	cpuid
	cmpl	$0x756e6547, %ebx	// "Genu"
	jne	done
	cmpl	$0x6c65746e, %ecx	// "ineI"
	jne	done
	cmpl	$0x49656e69, %edx	// "ntel"
	jne	done

	// CPUID leaf = 1, subleaf = 0
	movl	$1, %eax
	movl	$0, %ecx
	cpuid
	movl	%edx, %eax

	movl	36(%esp), %ebx
	movl	40(%esp), %edx
	shrl	$2, %edx
	xorl	%edi, %edi

	andl	$CPUIDECX_RDRAND, %ecx	// See if we have rdrand.
	jnz	userand

	movl	%edx, %ecx
	andl	$CPUID_TSC, %eax	// See if we have rdtsc.
	jnz	usetsc

	jmp	done

userand:
	rdrand	%eax
	xorl	%eax, (%ebx,%edi,4)
	incl	%edi
	cmpl	%edi, %edx
	jne	userand
	jmp	done

usetsc:
	rdtsc				// Populates edx:eax.
	mull	%edx
	xorl	%eax, (%ebx,%edi,4)
	incl	%edi
	cmpl	%edi, %ecx
	jne	usetsc
	jmp	done

done:
	popal
	ret


code:
/*	$OpenBSD: softraid.c,v 1.11 2015/07/21 03:30:51 krw Exp $	*/

/*
 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
 *
 * 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/queue.h>
#include <sys/disklabel.h>
#include <sys/reboot.h>

#include <dev/biovar.h>
#include <dev/softraidvar.h>

#include <lib/libsa/aes_xts.h>
#include <lib/libsa/hmac_sha1.h>
#include <lib/libsa/pbkdf2.h>
#include <lib/libsa/rijndael.h>

#include "libsa.h"
#include "biosdev.h"
#include "disk.h"
#include "softraid.h"

/* List of softraid volumes. */
struct sr_boot_volume_head sr_volumes;

/* Metadata from keydisks. */
struct sr_boot_keydisk {
	struct sr_uuid	kd_uuid;
	u_int8_t	kd_key[SR_CRYPTO_MAXKEYBYTES];
	SLIST_ENTRY(sr_boot_keydisk) kd_link;
};
SLIST_HEAD(sr_boot_keydisk_head, sr_boot_keydisk);
struct sr_boot_keydisk_head sr_keydisks;

void
srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
{
	struct sr_meta_opt_hdr	*omh;
	struct sr_meta_opt_item *omi;
#if 0
	u_int8_t checksum[MD5_DIGEST_LENGTH];
#endif
	int			i;

	/* Process optional metadata. */
	omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
	    sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
	for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {

#ifdef BIOS_DEBUG
		printf("Found optional metadata of type %u, length %u\n",
		    omh->som_type, omh->som_length);
#endif

		/* Unsupported old fixed length optional metadata. */
		if (omh->som_length == 0) {
			omh = (struct sr_meta_opt_hdr *)((void *)omh +
			    SR_OLD_META_OPT_SIZE);
			continue;
		}

		/* Load variable length optional metadata. */
		omi = alloc(sizeof(struct sr_meta_opt_item));
		bzero(omi, sizeof(struct sr_meta_opt_item));
		SLIST_INSERT_HEAD(som, omi, omi_link);
		omi->omi_som = alloc(omh->som_length);
		bzero(omi->omi_som, omh->som_length);
		bcopy(omh, omi->omi_som, omh->som_length);

#if 0
		/* XXX - Validate checksum. */
		bcopy(&omi->omi_som->som_checksum, &checksum,
		    MD5_DIGEST_LENGTH);
		bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH);
		sr_checksum(sc, omi->omi_som,
		    &omi->omi_som->som_checksum, omh->som_length);
		if (bcmp(&checksum, &omi->omi_som->som_checksum,
		    sizeof(checksum)))
			panic("%s: invalid optional metadata checksum",
			    DEVNAME(sc));
#endif

		omh = (struct sr_meta_opt_hdr *)((void *)omh +
		    omh->som_length);
	}
}

void
srprobe_keydisk_load(struct sr_metadata *sm)
{
	struct sr_meta_opt_hdr	*omh;
	struct sr_meta_keydisk	*skm;
	struct sr_boot_keydisk	*kd;
	int i;

	/* Process optional metadata. */
	omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
	    sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
	for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {

		/* Unsupported old fixed length optional metadata. */
		if (omh->som_length == 0) {
			omh = (struct sr_meta_opt_hdr *)((void *)omh +
			    SR_OLD_META_OPT_SIZE);
			continue;
		}

		if (omh->som_type != SR_OPT_KEYDISK) {
			omh = (struct sr_meta_opt_hdr *)((void *)omh +
			    omh->som_length);
			continue;
		}

		kd = alloc(sizeof(struct sr_boot_keydisk));
		bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid));
		skm = (struct sr_meta_keydisk*)omh;
		bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key));
		SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link);
	}
}

void
srprobe(void)
{
	struct sr_boot_volume *bv, *bv1, *bv2;
	struct sr_boot_chunk *bc, *bc1, *bc2;
	struct sr_meta_chunk *mc;
	struct sr_metadata *md;
	struct diskinfo *dip;
	struct partition *pp;
	int i, error, volno;
	dev_t bsd_dev;
	daddr_t off;

	/* Probe for softraid volumes. */
	SLIST_INIT(&sr_volumes);
	SLIST_INIT(&sr_keydisks);

	md = alloc(SR_META_SIZE * DEV_BSIZE);

	TAILQ_FOREACH(dip, &disklist, list) {

		/* Only check hard disks, skip those with I/O errors. */
		if ((dip->bios_info.bios_number & 0x80) == 0 ||
		    (dip->bios_info.flags & BDI_INVALID))
			continue;

		/* Make sure disklabel has been read. */
		if ((dip->bios_info.flags & (BDI_BADLABEL|BDI_GOODLABEL)) == 0)
			continue;

		for (i = 0; i < MAXPARTITIONS; i++) {

			pp = &dip->disklabel.d_partitions[i];
			if (pp->p_fstype != FS_RAID || pp->p_size == 0)
				continue;

			/* Read softraid metadata. */
			bzero(md, SR_META_SIZE * DEV_BSIZE);
			off = DL_SECTOBLK(&dip->disklabel, DL_GETPOFFSET(pp));
			off += SR_META_OFFSET;
			error = biosd_io(F_READ, &dip->bios_info, off,
			    SR_META_SIZE, md);
			if (error)
				continue;

			/* Is this valid softraid metadata? */
			if (md->ssdi.ssd_magic != SR_MAGIC)
				continue;

			/* XXX - validate checksum. */

			/* Handle key disks separately... */
			if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
				srprobe_keydisk_load(md);
				continue;
			}

			/* Locate chunk-specific metadata for this chunk. */
			mc = (struct sr_meta_chunk *)(md + 1);
			mc += md->ssdi.ssd_chunk_id;

			bc = alloc(sizeof(struct sr_boot_chunk));
			bc->sbc_diskinfo = dip;
			bc->sbc_disk = dip->bios_info.bios_number;
			bc->sbc_part = 'a' + i;

			bsd_dev = dip->bios_info.bsd_dev;
			bc->sbc_mm = MAKEBOOTDEV(B_TYPE(bsd_dev),
			    B_ADAPTOR(bsd_dev), B_CONTROLLER(bsd_dev),
			    B_UNIT(bsd_dev), bc->sbc_part - 'a');

			bc->sbc_chunk_id = md->ssdi.ssd_chunk_id;
			bc->sbc_ondisk = md->ssd_ondisk;
			bc->sbc_state = mc->scm_status;

			SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
				if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
				    sizeof(md->ssdi.ssd_uuid)) == 0)
					break;
			}

			if (bv == NULL) {
				bv = alloc(sizeof(struct sr_boot_volume));
				bzero(bv, sizeof(struct sr_boot_volume));
				bv->sbv_level = md->ssdi.ssd_level;
				bv->sbv_volid = md->ssdi.ssd_volid;
				bv->sbv_chunk_no = md->ssdi.ssd_chunk_no;
				bv->sbv_flags = md->ssdi.ssd_vol_flags;
				bv->sbv_size = md->ssdi.ssd_size;
				bv->sbv_data_blkno = md->ssd_data_blkno;
				bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
				    sizeof(md->ssdi.ssd_uuid));
				SLIST_INIT(&bv->sbv_chunks);
				SLIST_INIT(&bv->sbv_meta_opt);

				/* Load optional metadata for this volume. */
				srprobe_meta_opt_load(md, &bv->sbv_meta_opt);

				/* Maintain volume order. */
				bv2 = NULL;
				SLIST_FOREACH(bv1, &sr_volumes, sbv_link) {
					if (bv1->sbv_volid > bv->sbv_volid)
						break;
					bv2 = bv1;
				}
				if (bv2 == NULL)
					SLIST_INSERT_HEAD(&sr_volumes, bv,
					    sbv_link);
				else
					SLIST_INSERT_AFTER(bv2, bv, sbv_link);
			}

			/* Maintain chunk order. */
			bc2 = NULL;
			SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) {
				if (bc1->sbc_chunk_id > bc->sbc_chunk_id)
					break;
				bc2 = bc1;
			}
			if (bc2 == NULL)
				SLIST_INSERT_HEAD(&bv->sbv_chunks,
				    bc, sbc_link);
			else
				SLIST_INSERT_AFTER(bc2, bc, sbc_link);

			bv->sbv_chunks_found++;
		}
	}

	/*
	 * Assemble RAID volumes.
	 */
	volno = 0;
	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {

		/* Skip if this is a hotspare "volume". */
		if (bv->sbv_level == SR_HOTSPARE_LEVEL &&
		    bv->sbv_chunk_no == 1)
			continue;

		/* Determine current ondisk version. */
		bv->sbv_ondisk = 0;
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
			if (bc->sbc_ondisk > bv->sbv_ondisk)
				bv->sbv_ondisk = bc->sbc_ondisk;
		}
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
			if (bc->sbc_ondisk != bv->sbv_ondisk)
				bc->sbc_state = BIOC_SDOFFLINE;
		}

		/* XXX - Check for duplicate chunks. */

		/*
		 * Validate that volume has sufficient chunks for
		 * read-only access.
		 *
		 * XXX - check chunk states.
		 */
		bv->sbv_state = BIOC_SVOFFLINE;
		switch (bv->sbv_level) {
		case 0:
		case 'C':
		case 'c':
			if (bv->sbv_chunk_no == bv->sbv_chunks_found)
				bv->sbv_state = BIOC_SVONLINE;
			break;

		case 1:
			if (bv->sbv_chunk_no == bv->sbv_chunks_found)
				bv->sbv_state = BIOC_SVONLINE;
			else if (bv->sbv_chunks_found > 0)
				bv->sbv_state = BIOC_SVDEGRADED;
			break;
		}

		bv->sbv_unit = volno++;
		if (bv->sbv_state != BIOC_SVOFFLINE)
			printf(" sr%d%s", bv->sbv_unit,
			    bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
	}

	explicit_bzero(md, SR_META_SIZE * DEV_BSIZE);
	free(md, 0);
}

int
sr_strategy(struct sr_boot_volume *bv, int rw, daddr32_t blk, size_t size,
    void *buf, size_t *rsize)
{
	struct diskinfo *sr_dip, *dip;
	struct sr_boot_chunk *bc;
	struct aes_xts_ctx ctx;
	size_t i, j, nsect;
	daddr_t blkno;
	u_char iv[8];
	u_char *bp;
	int err;

	/* We only support read-only softraid. */
	if (rw != F_READ)
		return ENOTSUP;

	/* Partition offset within softraid volume. */
	sr_dip = (struct diskinfo *)bv->sbv_diskinfo;
	blk += sr_dip->disklabel.d_partitions[bv->sbv_part - 'a'].p_offset;

	if (bv->sbv_level == 0) {
		return ENOTSUP;
	} else if (bv->sbv_level == 1) {

		/* Select first online chunk. */
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
			if (bc->sbc_state == BIOC_SDONLINE)
				break;
		if (bc == NULL)
			return EIO;

		dip = (struct diskinfo *)bc->sbc_diskinfo;
		dip->bsddev = bc->sbc_mm;
		blk += bv->sbv_data_blkno;

		/* XXX - If I/O failed we should try another chunk... */
		return biosstrategy(dip, rw, blk, size, buf, rsize);

	} else if (bv->sbv_level == 'C') {

		/* Select first online chunk. */
		SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
			if (bc->sbc_state == BIOC_SDONLINE)
				break;
		if (bc == NULL)
			return EIO;

		dip = (struct diskinfo *)bc->sbc_diskinfo;
		dip->bsddev = bc->sbc_mm;

		/* XXX - select correct key. */
		aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64);

		nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
		for (i = 0; i < nsect; i++) {
			blkno = blk + i;
			bp = ((u_char *)buf) + i * DEV_BSIZE;
			err = biosstrategy(dip, rw, bv->sbv_data_blkno + blkno,
			    DEV_BSIZE, bp, NULL);
			if (err != 0)
				return err;

			bcopy(&blkno, iv, sizeof(blkno));
			aes_xts_reinit(&ctx, iv);
			for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE)
				aes_xts_decrypt(&ctx, bp + j);
		}
		if (rsize != NULL)
			*rsize = nsect * DEV_BSIZE;

		return err;

	} else
		return ENOTSUP;
}

const char *
sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
{
	struct dos_partition *dp;
	struct dos_mbr mbr;
	u_int start = 0;
	char *buf;
	int i;

	/* Check for MBR to determine partition offset. */
	bzero(&mbr, sizeof(mbr));
	sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(mbr), &mbr, NULL);
	if (mbr.dmbr_sign == DOSMBR_SIGNATURE) {

		/* Search for OpenBSD partition */
		for (i = 0; i < NDOSPART; i++) {
			dp = &mbr.dmbr_parts[i];
			if (!dp->dp_size)
				continue;
			if (dp->dp_typ == DOSPTYP_OPENBSD) {
				if (dp->dp_start > (dp->dp_start + DOSBBSECTOR))
					continue;
				start = dp->dp_start + DOSBBSECTOR;
			}
		}
	}

	start += LABELSECTOR;

	/* Read the disklabel. */
	buf = alloca(DEV_BSIZE);
	sr_strategy(bv, F_READ, start, sizeof(struct disklabel), buf, NULL);

#ifdef BIOS_DEBUG
	printf("sr_getdisklabel: magic %lx\n",
	    ((struct disklabel *)buf)->d_magic);
	for (i = 0; i < MAXPARTITIONS; i++)
		printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i,
		    (int)((struct disklabel *)buf)->d_partitions[i].p_fstype,
		    (int)((struct disklabel *)buf)->d_partitions[i].p_size,
		    (int)((struct disklabel *)buf)->d_partitions[i].p_offset);
#endif

	/* Fill in disklabel */
	return (getdisklabel(buf, label));
}

#define RIJNDAEL128_BLOCK_LEN     16
#define PASSPHRASE_LENGTH 1024

#define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES

#ifdef BIOS_DEBUG
void
printhex(const char *s, const u_int8_t *buf, size_t len)
{
	u_int8_t n1, n2;
	size_t i;

	printf("%s: ", s);
	for (i = 0; i < len; i++) {
		n1 = buf[i] & 0x0f;
		n2 = buf[i] >> 4;
		printf("%c", n2 > 9 ? n2 + 'a' - 10 : n2 + '0');
		printf("%c", n1 > 9 ? n1 + 'a' - 10 : n1 + '0');
	}
	printf("\n");
}
#endif

void
sr_clear_keys(void)
{
	struct sr_boot_volume *bv;
	struct sr_boot_keydisk *kd;

	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
		if (bv->sbv_level != 'C')
			continue;
		if (bv->sbv_keys != NULL) {
			explicit_bzero(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
			free(bv->sbv_keys, 0);
			bv->sbv_keys = NULL;
		}
		if (bv->sbv_maskkey != NULL) {
			explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
			free(bv->sbv_maskkey, 0);
			bv->sbv_maskkey = NULL;
		}
	}
	SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
		explicit_bzero(kd, sizeof(*kd));
		free(kd, 0);
	}
}

void
sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
    u_int8_t *key, int key_size, u_char *check_digest)
{
	u_int8_t check_key[SHA1_DIGEST_LENGTH];
	SHA1_CTX shactx;

	explicit_bzero(check_key, sizeof(check_key));
	explicit_bzero(&shactx, sizeof(shactx));

	/* k = SHA1(mask_key) */
	SHA1Init(&shactx);
	SHA1Update(&shactx, maskkey, maskkey_size);
	SHA1Final(check_key, &shactx);

	/* mac = HMAC_SHA1_k(unencrypted key) */
	hmac_sha1(key, key_size, check_key, sizeof(check_key), check_digest);

	explicit_bzero(check_key, sizeof(check_key));
	explicit_bzero(&shactx, sizeof(shactx));
}

int
sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
{
	struct sr_meta_crypto *cm;
	struct sr_boot_keydisk	*kd;
	struct sr_meta_opt_item *omi;
	struct sr_crypto_kdf_pbkdf2 *kdfhint;
	struct sr_crypto_kdfinfo kdfinfo;
	char passphrase[PASSPHRASE_LENGTH];
	u_int8_t digest[SHA1_DIGEST_LENGTH];
	u_int8_t *keys = NULL;
	u_int8_t *kp, *cp;
	rijndael_ctx ctx;
	int rv = -1;
	int c, i;

	SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
		if (omi->omi_som->som_type == SR_OPT_CRYPTO)
			break;

	if (omi == NULL) {
		printf("Crypto metadata not found!\n");
		goto done;
	}

	cm = (struct sr_meta_crypto *)omi->omi_som;
	kdfhint = (struct sr_crypto_kdf_pbkdf2 *)&cm->scm_kdfhint;

	switch (cm->scm_mask_alg) {
	case SR_CRYPTOM_AES_ECB_256:
		break;
	default:
		printf("unsupported encryption algorithm %u\n",
		    cm->scm_mask_alg);
		goto done;
	}

	SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
		if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0)
			break;
	}
	if (kd) {
		bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
	} else {
		printf("Passphrase: ");
		for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
			c = cngetc();
			if (c == '\r' || c == '\n')
				break;
			passphrase[i] = (c & 0xff);
		}
		passphrase[i] = 0;
		printf("\n");

#ifdef BIOS_DEBUG
		printf("Got passphrase: %s with len %d\n",
		    passphrase, strlen(passphrase));
#endif

		if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt,
		    sizeof(kdfhint->salt), kdfinfo.maskkey,
		    sizeof(kdfinfo.maskkey), kdfhint->rounds) != 0) {
			printf("pbkdf2 failed\n");
			goto done;
		}
	}

	/* kdfinfo->maskkey now has key. */

	/* Decrypt disk keys. */
	keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
	bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);

	if (rijndael_set_key(&ctx, kdfinfo.maskkey, 256) != 0)
		goto done;

	cp = (u_int8_t *)cm->scm_key;
	kp = keys;
	for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN)
		rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i));

	/* Check that the key decrypted properly. */
	sr_crypto_calculate_check_hmac_sha1(kdfinfo.maskkey,
	    sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest);

	if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) {
		printf("incorrect passphrase or keydisk\n");
		goto done;
	}

	/* Keys and keydisks will be cleared before boot and from _rtt. */
	bv->sbv_keys = keys;
	bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
	bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));

	rv = 0;

done:
	explicit_bzero(passphrase, PASSPHRASE_LENGTH);
	explicit_bzero(&kdfinfo, sizeof(kdfinfo));
	explicit_bzero(digest, sizeof(digest));

	if (keys != NULL && rv != 0) {
		explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
		free(keys, 0);
	}

	return (rv);
}

license: unknown


code:
/*	$OpenBSD: softraid.h,v 1.1 2012/10/27 15:43:42 jsing Exp $	*/

/*
 * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
 *
 * 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.
 */

#ifndef _SOFTRAID_H_
#define _SOFTRAID_H_

void	srprobe(void);

const char *sr_getdisklabel(struct sr_boot_volume *, struct disklabel *);
int	sr_strategy(struct sr_boot_volume *, int, daddr32_t, size_t,
	    void *, size_t *);

int	sr_crypto_decrypt_keys(struct sr_boot_volume *);
void	sr_clear_keys(void);

/* List of softraid volumes. */
extern struct sr_boot_volume_head sr_volumes;

#endif /* _SOFTRAID_H */


code:
/*	$OpenBSD: time.c,v 1.5 2014/09/23 17:59:25 brad Exp $	*/

/*
 * Copyright (c) 1997 Michael Shalayeff
 * Copyright (c) 1997 Tobias Weingartner
 * 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 REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

#include <sys/time.h>
#include <machine/biosvar.h>
#include <machine/pio.h>
#include "libsa.h"
#include "biosdev.h"

#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)

/*
 * Convert from bcd (packed) to int
 */
static __inline u_int8_t
bcdtoint(u_int8_t c)
{
	return ((c & 0xf0) / 8) * 5 + (c & 0x0f);
}

/*
 * Quick compute of time in seconds since the Epoch
 */
const u_short monthcount[] = {
	0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
};

static __inline time_t
compute(int year, u_int8_t month, u_int8_t day, u_int8_t hour,
    u_int8_t min, u_int8_t sec)
{
	/* Number of days per month */
	register time_t tt;

	/* Compute days */
	tt = (year - 1970) * 365 + monthcount[month] + day - 1;

	/* Compute for leap year */
	for (month <= 2 ? year-- : 0; year >= 1970; year--)
		if (isleap(year))
			tt++;

	/* Plus the time */
	tt = sec + 60 * (min + 60 * (tt * 24 + hour));

	return tt;
}

static int
bios_time_date(int f, u_int8_t *b)
{
	__asm volatile(DOINT(0x1a) "\n\t"
	    "setc %b0\n\t"
	    "movb %%ch, 0(%2)\n\t"
	    "movb %%cl, 1(%2)\n\t"
	    "movb %%dh, 2(%2)\n\t"
	    "movb %%dl, 3(%2)\n\t"
	    : "=a" (f)
	    : "0" (f), "r" (b) : "%ecx", "%edx", "cc");

	if (f & 0xff)
		return -1;
	else {
		b[0] = bcdtoint(b[0]);
		b[1] = bcdtoint(b[1]);
		b[2] = bcdtoint(b[2]);
		b[3] = bcdtoint(b[3]);
		return 0;
	}
}

static __inline int
biosdate(u_int8_t *b)
{
	return bios_time_date(4 << 8, b);
}

static __inline int
biostime(u_int8_t *b)
{
	return bios_time_date(2 << 8, b);
}

/*
 * Return time since epoch
 */
time_t
getsecs(void)
{
	u_int8_t timebuf[4], datebuf[4];

	/* Query BIOS for time & date */
	if (!biostime(timebuf) && !biosdate(datebuf)) {
#ifdef notdef
		int dst;

		dst = timebuf[3];
#endif
		/* Convert to seconds since Epoch */
		return compute(datebuf[0] * 100 + datebuf[1], datebuf[2],
		    datebuf[3], timebuf[0], timebuf[1], timebuf[2]);
	} else
		errno = EIO;

	return 1;
}

u_int
sleep(u_int i)
{
	register time_t t;

	/*
	 * Loop for the requested number of seconds, polling BIOS,
	 * so that it may handle interrupts.
	 */
	for (t = getsecs() + i; getsecs() < t; cnischar())
		;

	return 0;
}


code:
#	$OpenBSD: Makefile,v 1.10 2014/07/13 21:18:44 jasper Exp $
#

S=	${.CURDIR}/../../../..
SADIR=	${.CURDIR}/..

PROG=	mbr
SRCS=	mbr.S
AFLAGS+=-m32
AFLAGS+=-I${.CURDIR} -I${.CURDIR}/../../.. #-Wa,-a
AFLAGS+=-fno-pie
LD=ld
LDFLAGS=-nostdlib -Ttext 0 -x -N -s -Bstatic -e start -nopie
LDFLAGS+=-melf_i386 -L/usr/libdata

NOMAN=
#MAN+=	mbr.8

INSTALL_STRIP=

# Uncomment this to make mbr talk to a serial port.
#CPPFLAGS+=-DSERIAL=0

.depend mbr.o: assym.h

${PROG}: $(OBJS)
	$(LD) $(LDFLAGS) -o $(PROG) $(OBJS)
	@size $(PROG)
	@if [ -x ${.OBJDIR}/${PROG} ]; then \
		objcopy -O binary ${PROG} ${.OBJDIR}/.tmp;\
		mv -f ${.OBJDIR}/.tmp ${.OBJDIR}/${PROG}; \
		ls -l ${.OBJDIR}/${PROG}; \
	fi

.include <bsd.prog.mk>


code:
/*	$OpenBSD: mbr.S,v 1.5 2012/06/04 16:17:04 mglocker Exp $	*/

/*
 * Copyright (c) 1997 Michael Shalayeff and Tobias Weingartner
 * Copyright (c) 2003 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
 * 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 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.
 *
 */
/* Copyright (c) 1996 VaX#n8 (vax@linkdead.paranoia.com)
 * last edited 9 July 1996
 * many thanks to Erich Boleyn (erich@uruk.org) for putting up with
 * all my questions, and for his work on GRUB
 * You may use this code or fragments thereof in a manner consistent
 * with the other copyrights as long as you retain my pseudonym and
 * this copyright notice in the file.
 */

	.file	"mbr.S"

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

/*
 * Memory layout:
 *
 * 0x07C00 -> 0x07DFF	BIOS loads us here	(at  31k)
 * 0x07E00 -> 0x17BFC	our stack		(to  95k)
 *
 * 0x07A00 -> 0x07BFF	we relocate to here	(at  30k5)
 *
 * 0x07C00 -> 0x07DFF	we load PBR here	(at  31k)
 *
 * The BIOS loads us at physical address 0x07C00.  We use a long jmp to
 * normalise our address to seg:offset 07C0:0000.  We then relocate to
 * 0x07A00, seg:offset 07A0:0000.
 *
 * We use a long jmp to normalise our address to seg:offset 07A0:0000
 * We set the stack to start at 07C0:FFFC (grows down on i386)
 * The partition boot record (PBR) loads /boot at seg:offset 4000:0000
 */
#define BOOTSEG		0x7c0	/* segment where we are loaded */
#define BOOTRELOCSEG	0x7a0	/* segment where we relocate to */
#define BOOTSTACKOFF	0xfffc	/* stack starts here, grows down */
#define PARTSZ		16	/* each partition table entry is 16 bytes */

#define CHAR_LBA_READ	'.'
#define CHAR_CHS_READ	';'
#define CHAR_SHIFT_SEEN	0x07	/* Use BEL */

#define MBR_FLAGS_FORCE_CHS	0x0001

#ifdef DEBUG
#define CHAR_S		'S'	/* started */
#define CHAR_R		'R'	/* relocated */
#define CHAR_L		'L'	/* looking for bootable partition */
#define CHAR_B		'B'	/* loading boot */
#define CHAR_G		'G'	/* jumping to boot */

#define DBGMSG(c)	movb	$c, %al;	call	Lchr
#else /* !DEBUG */
#define DBGMSG(c)
#endif /* !DEBUG */

/* Clobbers %al - maybe more */
#define	putc(c)		movb	$c, %al;	call	Lchr

/* Clobbers %esi - maybe more */
#define	puts(s)		movw	$s, %si;	call	Lmessage

	.text
	.code16

	.globl	start
start:
	/* Adjust %cs to be right */
	ljmp 	$BOOTSEG, $1f
1:
	/* Set up stack */
	movw	%cs, %ax

	/*
	 * We don't need to disable and re-enable interrupts around the
	 * the load of ss and sp.
	 *
	 * From 80386 Programmer's Reference Manual:
	 * "A MOV into SS inhibits all interrupts until after the execution
	 * of the next instruction (which is presumably a MOV into eSP)"
	 *
	 * According to Hamarsoft's 86BUGS list (which is distributed with
	 * Ralph Brown's Interrupt List), some early 8086/88 processors
	 * failed to disable interrupts following a load into a segment
	 * register, but this was fixed with later steppings.
	 *
	 * Accordingly, this code will fail on very early 8086/88s, but
	 * nick@ will just have to live with it.  Others will note that
	 * we require an 80386 (or compatible) or above processor, anyway.
	 */
	/* cli */
	movw	%ax, %ss
	movw	$BOOTSTACKOFF, %sp
	/* sti */			/* XXX not necessary; see above */

	/* Set up data segment */
	movw	%ax, %ds
	DBGMSG(CHAR_S)

	/*
	 * On the PC architecture, the boot record (originally on a floppy
	 * disk) is loaded at 0000:7C00 (hex) and execution starts at the
	 * beginning.
	 *
	 * When hard disk support was added, a scheme to partition disks into
	 * four separate partitions was used, to allow multiple operating
	 * systems to be installed on the one disk.  The boot sectors of the
	 * operating systems on each partition would of course expect to be
	 * loaded at 0000:7C00.
	 *
	 * The first sector of the hard disk is the master boot record (MBR).
	 * It is this which defines the partitions and says which one is
	 * bootable.  Of course, the BIOS loads the MBR at 0000:7C00, the
	 * same location where the MBR needs to load the partition boot
	 * record (PBR, called biosboot in OpenBSD).
	 *
	 * Therefore, the MBR needs to relocate itself before loading the PBR.
	 *
	 * Make it so.
	 */
	movw	$BOOTRELOCSEG, %ax
	movw	%ax, %es
	xorw	%si, %si
	xorw	%di, %di
	movw	$0x200, %cx		/* Bytes in MBR, relocate it all */
	cld
	rep
	movsb

	/* Jump to relocated self */
	ljmp $BOOTRELOCSEG, $reloc
reloc:
	DBGMSG(CHAR_R)

	/* Set up %es and %ds */
	pushw	%ds
	popw	%es	/* next boot is at the same place as we were loaded */
	pushw	%cs
	popw	%ds	/* and %ds is at the %cs */

#ifdef SERIAL
	/* Initialize the serial port to 9600 baud, 8N1.
	 */
	pushw	%dx
	xorw	%ax, %ax
	movb	$0xe3, %ax
	movw	$SERIAL, %dx
	int	$0x14
	popw	%dx
#endif

	/*
	 * If the SHIFT key is held down on entry, force CHS read
	 */

	/*
	 * BIOS call "INT 0x16 Get Keyboard Shift Flags
	 *	Call with	%ah = 0x02
	 *	Return:
	 *			%al = shift flags
	 *			%ah - undefined by many BIOSes
	 */
	movb	$0x02, %ah
	int	$0x16
	testb	$0x3, %al	/* Either shift key down? */
	jz	no_shift

	putc(CHAR_SHIFT_SEEN)	/* Signal that shift key was seen */

	orb	$MBR_FLAGS_FORCE_CHS, flags

no_shift:
	/* BIOS passes us drive number in %dl
	 *
	 * XXX - This is not always true.  We currently check if %dl
	 * points to a HD, and if not we complain, and set it to point
	 * to the first HDD.  Note, this is not 100% correct, since
	 * there is a possibility that you boot from HD #2, and still
	 * get (%dl & 0x80) == 0x00, these type of systems will lose.
	 */
	testb	$0x80, %dl
	jnz	drive_ok

	/* MBR on floppy or old BIOS
	 * Note: MBR (this code) should never be on a floppy.  It does
	 * not belong there, so %dl should never be 0x00.
	 *
	 * Here we simply complain (should we?), and then hardcode the
	 * boot drive to 0x80.
	 */
	puts(efdmbr)

	/* If we are passed bogus data, set it to HD #1
	 */
	movb	$0x80, %dl

drive_ok:
	/* Find the first active partition.
	 * Note: this should be the only active partition.  We currently
	 * don't check for that.
	 */
	movw	$pt, %si

	movw	$NDOSPART, %cx
find_active:
	DBGMSG(CHAR_L)
	movb	(%si), %al

	cmpb	$DOSACTIVE, %al
	je	found

	addw	$PARTSZ, %si
	loop	find_active

	/* No bootable partition */
no_part:
	movw	$enoboot, %si

err_stop:
	call	Lmessage

stay_stopped:
	sti				/* Ensure Ctl-Alt-Del will work */
	hlt
	/* Just to make sure */
	jmp	stay_stopped

found:
	/*
	 * Found bootable partition
	 */

	DBGMSG(CHAR_B)

	/* Store the drive number (from %dl) in decimal */
	movb	%dl, %al
	andb	$0x0F, %al
	addb	$'0', %al
	movb	%al, drive_num

	/*
	 * Store the partition number, in decimal.
	 *
	 * We started with cx = 4; if found we want part '0'
	 *                 cx = 3;                  part '1'
	 *                 cx = 2;                  part '2'
	 *                 cx = 1;                  part '3'
	 *
	 * We'll come into this with no other values for cl.
	 */
	movb	$'0'+4, %al
	subb	%cl, %al
	movb	%al, part_num

	/*
	 * Tell operator what partition we're trying to boot.
	 *
	 * Using drive X, partition Y
	 * - this used to be printed out after successfully loading the
	 *   partition boot record; we now print it out before
	 */
	pushw	%si
	movw	$info, %si
	testb	$MBR_FLAGS_FORCE_CHS, flags
	jnz	1f
	incw	%si
1:
	call	Lmessage
	popw	%si

	/*
	 * Partition table entry format:
	 *
	 * 0x00	BYTE boot indicator (0x80 = active, 0x00 = inactive)
	 * 0x01	BYTE start head
	 * 0x02	WORD start cylinder, sector
	 * 0x04	BYTE system type (0xA6 = OpenBSD)
	 * 0x05 BYTE end head
	 * 0x06	WORD end cylinder, sector
	 * 0x08	LONG start LBA sector
	 * 0x0C	LONG number of sectors in partition
	 *
	 * In the case of a partition that extends beyond the 8GB boundary,
	 * the LBA values will be correct, the CHS values will have their
	 * maximums (typically (C,H,S) = (1023,255,63)).
	 *
	 * %ds:%si points to the active partition table entry.
	 */

	/* We will load the partition boot sector (biosboot) where we
	 * were originally loaded.  We'll check to make sure something
	 * valid comes in.  So that we don't find ourselves, zero out
	 * the signature at the end.
	 */
	movw	$0, %es:signature(,1)

	/*
	 * Have we been instructed to ignore LBA?
	 */
	testb	$MBR_FLAGS_FORCE_CHS, flags
	jnz	do_chs

	/*
	 * We will use the LBA sector number if we have LBA support,
	 * so find out.
	 */

	/*
	 * BIOS call "INT 0x13 Extensions Installation Check"
	 *	Call with	%ah = 0x41
	 *			%bx = 0x55AA
	 *			%dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
	 *	Return:
	 *			carry set: failure
	 *				%ah = error code (0x01, invalid func)
	 *			carry clear: success
	 *				%bx = 0xAA55 (must verify)
	 *				%ah = major version of extensions
	 *				%al   (internal use)
	 *				%cx = capabilities bitmap
	 *					0x0001 - extnd disk access funcs
	 *					0x0002 - rem. drive ctrl funcs
	 *					0x0004 - EDD functions with EBP
	 *				%dx   (extension version?)
	 */

	movb	%dl, (%si)		/* Store drive here temporarily */
					/* (This call trashes %dl) */
					/*
					 * XXX This is actually the correct
					 *     place to store this.  The 0x80
					 *     value used to indicate the
					 *     active partition is by intention
					 *     the same as the BIOS drive value
					 *     for the first hard disk (0x80).
					 *     At one point, 0x81 would go here
					 *     for the second hard disk; the
					 *     0x80 value is often used as a
					 *     bit flag for testing, rather
					 *     than an exact byte value.
					 */
	movw	$0x55AA, %bx
	movb	$0x41, %ah
	int	$0x13

	movb	(%si), %dl		/* Get back drive number */

	jc	do_chs			/* Did the command work? Jump if not */
	cmpw	$0xAA55, %bx		/* Check that bl, bh exchanged */
	jne	do_chs			/* If not, don't have EDD extensions */
	testb	$0x01, %cl		/* And do we have "read" available? */
	jz	do_chs			/* Again, use CHS if not */

do_lba:
	/*
	 * BIOS call "INT 0x13 Extensions Extended Read"
	 *	Call with	%ah = 0x42
	 *			%dl = drive (0x80 for 1st hd, 0x81 for 2nd, etc)
	 *			%ds:%si = segment:offset of command packet
	 *	Return:
	 *			carry set: failure
	 *				%ah = error code (0x01, invalid func)
	 *				command packet's sector count field set
	 *				to the number of sectors successfully
	 *				transferred
	 *			carry clear: success
	 *				%ah = 0 (success)
	 *	Command Packet:
	 *			0x0000	BYTE	packet size (0x10 or 0x18)
	 *			0x0001	BYTE	reserved (should be 0)
	 *			0x0002	WORD	sectors to transfer (max 127)
	 *			0x0004	DWORD	seg:offset of transfer buffer
	 *			0x0008	QWORD	starting sector number
	 */
	movb	$CHAR_LBA_READ, %al
	call	Lchr

	/* Load LBA sector number from active partition table entry */
	movl	8(%si), %ecx
	movl	%ecx, lba_sector

	pushw	%si			/* We'll need %si later */

	movb	$0x42, %ah
	movw	$lba_command, %si
	int	$0x13

	popw	%si			/* (get back %si) flags unchanged */

	jnc	booting_os		/* If it worked, run the pbr we got */

	/*
	 * LBA read failed, fall through to try CHS read
	 */

do_chs:
	/*
	 * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into
	 * memory
	 *       Call with       %ah = 0x2
	 *                       %al = number of sectors
	 *                       %ch = cylinder & 0xFF
	 *                       %cl = sector (0-63) | rest of cylinder bits
	 *                       %dh = head
	 *                       %dl = drive (0x80 for hard disk)
	 *                       %es:%bx = segment:offset of buffer
	 *       Return:
	 *                       carry set: failure
	 *                           %ah = err code
	 *                           %al = number of sectors transferred
	 *                       carry clear: success
	 *                           %al = 0x0 OR number of sectors transferred
	 *                                 (depends on BIOS!)
	 *                                 (according to Ralph Brown Int List)
	 */
	movb	$CHAR_CHS_READ, %al
	call	Lchr

	/* Load values from active partition table entry */
	movb	1(%si), %dh		/* head */
	movw	2(%si), %cx		/* sect, cyl */
	movw	$0x201, %ax		/* function and number of blocks */
	xorw	%bx, %bx		/* put it at %es:0 */
	int	$0x13
	jnc	booting_os

read_error:
	movw	$eread, %si
	jmp	err_stop

booting_os:
	puts(crlf)
	DBGMSG(CHAR_G)

	/*
	 * Make sure the pbr we loaded has a valid signature at the end.
	 * This also ensures that something did load where we were expecting
	 * it, as there's still a copy of our code there...
	 */
	cmpw	$DOSMBR_SIGNATURE, %es:signature(,1)
	jne	missing_os

	/* jump to the new code (%ds:%si is at the right point) */
	ljmp	$0, $BOOTSEG << 4
	/* not reached */

missing_os:
	movw	$enoos, %si
	jmp	err_stop

/*
 * Display string
 */
Lmessage:
	pushw	%ax
	cld
1:
	lodsb			/* %al = *%si++ */
	testb	%al, %al
	jz	1f
	call    Lchr
	jmp	1b

/*
 *	Lchr: write the error message in %ds:%si to console
 */
Lchr:
	pushw	%ax

#ifdef SERIAL
	pushw	%dx
	movb	$0x01, %ah
	movw	$SERIAL, %dx
	int	$0x14
	popw	%dx
#else
	pushw	%bx
	movb	$0x0e, %ah
	movw	$1, %bx
	int	$0x10
	popw	%bx
#endif
1:	popw	%ax
	ret

/* command packet for LBA read of boot sector */
lba_command:
	.byte	0x10			/* size of command packet */
	.byte	0x00			/* reserved */
	.word	0x0001			/* sectors to transfer, just 1 */
	.word	0			/* target buffer, offset */
	.word	BOOTSEG			/* target buffer, segment */
lba_sector:
	.long	0, 0			/* sector number */

/* Info messages */
info:	.ascii		"!Using drive "
drive_num:
	.byte		'X'
	.ascii		", partition "
part_num:
	.asciz		"Y"

/* Error messages */
efdmbr:	.asciz		"MBR on floppy or old BIOS\r\n"
eread:	.asciz		"\r\nRead error\r\n"
enoos:	.asciz		"No O/S\r\n"
enoboot: .ascii		"No active partition"	/* runs into crlf... */
crlf:	.asciz		"\r\n"

endofcode:
	nop

/* We're going to store a flags word here */

	. = 0x1b4
flags:
	.word	0x0000
	.ascii	"Ox"			/* Indicate that the two bytes */
					/* before us are the flags word */

/* (MBR) NT disk signature offset */
	. = 0x1b8
	.space  4, 0

/* partition table */
/* flag, head, sec, cyl, type, ehead, esect, ecyl, start, len */
	. = DOSPARTOFF	/* starting address of partition table */
pt:
	.byte	0x0,0,0,0,0,0,0,0
	.long	0,0
	.byte	0x0,0,0,0,0,0,0,0
	.long	0,0
	.byte	0x0,0,0,0,0,0,0,0
	.long	0,0
	.byte	DOSACTIVE,0,1,0,DOSPTYP_OPENBSD,255,255,255
	.long	0,0x7FFFFFFF
/* the last 2 bytes in the sector 0 contain the signature */
	. = 0x1fe
signature:
	.short	DOSMBR_SIGNATURE
	. = 0x200


code:
#	$OpenBSD: Makefile,v 1.23 2014/11/19 20:09:58 miod Exp $

MAN=	pxeboot.8

.if ${MACHINE} == "amd64"
S=	${.CURDIR}/../../../..
SADIR=	${.CURDIR}/..

PROG=	pxeboot
SRCS=	srt0.S conf.c devopen.c open.c
LD?=	ld
SIZE?=	size
LDFLAGS+=-nostdlib -Bstatic -Ttext $(LINKADDR) -N -x -nopie
LDFLAGS+=-melf_i386 -L/usr/libdata
INSTALL_STRIP=
BINMODE=644

.PATH:	${SADIR}/libsa
# i386 stuff (so, it will possibly load in the same 64k)
SRCS+=	machdep.c exec_i386.c cmd_i386.c
SRCS+=	gidt.S random_i386.S alloca.S biosdev.c bioscons.c gateA20.c \
	memprobe.c diskprobe.c time.c ## biosprobe.c
SRCS+=	pxe.c pxe_call.S pxe_net.c pxe_udp.c
SRCS+=	softraid.c

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

.PATH:	${S}/lib/libsa
SRCS+=	alloc.c exit.c getchar.c getfile.c gets.c globals.c putchar.c strcmp.c \
	strlen.c strncmp.c memcmp.c memcpy.c memset.c printf.c snprintf.c \
	strerror.c strncpy.c strtol.c strtoll.c ctime.c strlcpy.c strlcat.c
SRCS+=	aes_xts.c explicit_bzero.c hmac_sha1.c pbkdf2.c rijndael.c sha1.c

SRCS+=	close.c closeall.c dev.c disklabel.c dkcksum.c fstat.c ioctl.c lseek.c \
	read.c stat.c write.c cread.c readdir.c cons.c loadfile.c \
	elf32.c elf64.c
SRCS+=	ether.c net.c netif.c rpc.c
SRCS+=	bootp.c bootparam.c
SRCS+=	ufs.c nfs.c tftp.c

.PATH:	${S}/lib/libkern/arch/amd64 ${S}/lib/libkern
SRCS+=	divdi3.c moddi3.c qdivrem.c udivdi3.c umoddi3.c

.PATH:	${S}/lib/libz
SRCS+=	adler32.c crc32.c inflate.c inftrees.c

.depend srt0.o gidt.o pxe_call.o: assym.h

${PROG}: $(OBJS)
	$(LD) $(LDFLAGS) -o ${PROG} $(OBJS)
	@$(SIZE) $(PROG)
	@if [ -x ${.OBJDIR}/${PROG} ]; then \
		objcopy -O binary ${PROG} ${.OBJDIR}/.tmp;\
		mv -f ${.OBJDIR}/.tmp ${.OBJDIR}/${PROG}; \
		ls -l ${.OBJDIR}/${PROG}; \
	fi

.else
NOPROG=
.endif

.include <bsd.prog.mk>

CPPFLAGS+=-DSOFTRAID
CPPFLAGS+=-DBOOTMAGIC=$(BOOTMAGIC) ${DEBUGFLAGS} -DLINKADDR=${LINKADDR}
CPPFLAGS+=-DSLOW -DSMALL -DNOBYFOUR -DNO_GZIP -DDYNAMIC_CRC_TABLE
CPPFLAGS+=-DHEAP_LIMIT=${HEAP_LIMIT} -I${S}/stand/boot #-DCOMPAT_UFS
CFLAGS+=-m32
CFLAGS+=$(SACFLAGS) -D__INTERNAL_LIBSA_CREAD -fno-pie
# AFLAGS+=-Wa,-a
AFLAGS+=-m32 # -Wa,-R
AFLAGS+=-fno-pie


code:
/*	$OpenBSD: conf.c,v 1.30 2014/02/18 13:56:02 jsing Exp $	*/

/*
 * Copyright (c) 2004 Tom Cosgrove
 * Copyright (c) 1996 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 REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <libsa.h>
#include <lib/libsa/ufs.h>
#ifdef notdef
#include <lib/libsa/cd9660.h>
#include <lib/libsa/fat.h>
#endif
#include <lib/libsa/nfs.h>
#include <lib/libsa/tftp.h>
#include <lib/libsa/netif.h>
#include <lib/libsa/unixdev.h>
#include <biosdev.h>
#include <dev/cons.h>
#include "pxeboot.h"
#include "pxe_net.h"

const char version[] = "3.23";
int	debug = 0;

#undef _TEST

void (*sa_cleanup)(void) = pxe_shutdown;

void (*i386_probe1[])(void) = {
	gateA20on, cninit, pxeprobe, memprobe
};
void (*i386_probe2[])(void) = {
	diskprobe
};
void (*i386_probe3[])(void) = {
	pxeinfo
/*	netprobe_pxe, netprobe_mac, netprobe_inet4, netprobe_bootdev */
};

struct i386_boot_probes probe_list[] = {
	{ "probing", i386_probe1, nitems(i386_probe1) },
	{ "disk",    i386_probe2, nitems(i386_probe2) },
	{ "net",     i386_probe3, nitems(i386_probe3) },
};
int nibprobes = nitems(probe_list);

/* This next list must match file_system[]. */
char *fs_name[] = {
	NULL, "tftp", "nfs"
};
int nfsname = nitems(fs_name);

struct fs_ops file_system[] = {
	{ ufs_open,    ufs_close,    ufs_read,    ufs_write,    ufs_seek,
	  ufs_stat,    ufs_readdir    },
	{ tftp_open,   tftp_close,   tftp_read,   tftp_write,   tftp_seek,
	  tftp_stat,   tftp_readdir   },
	{ nfs_open,    nfs_close,    nfs_read,    nfs_write,    nfs_seek,
	  nfs_stat,    nfs_readdir    },
#ifdef notdef
	{ fat_open,    fat_close,    fat_read,    fat_write,    fat_seek,
	  fat_stat,    fat_readdir    },
	{ cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
	  cd9660_stat, cd9660_readdir },
#endif
#ifdef _TEST
	{ null_open,   null_close,   null_read,   null_write,   null_seek,
	  null_stat,   null_readdir   }
#endif
};
int nfsys = nitems(file_system);

struct devsw	devsw[] = {
#ifdef _TEST
	{ "UNIX", unixstrategy, unixopen, unixclose, unixioctl },
#else
	{ "BIOS", biosstrategy, biosopen, biosclose, biosioctl },
#endif
};
int ndevs = nitems(devsw);

struct devsw	netsw[] = {
	{ "net",  net_strategy, net_open, net_close, net_ioctl },
};

struct netif_driver	*netif_drivers[] = {
};
int n_netif_drivers = nitems(netif_drivers);

struct consdev constab[] = {
#ifdef _TEST
	{ unix_probe, unix_init, unix_getc, unix_putc },
#else
	{ pc_probe, pc_init, pc_getc, pc_putc },
	{ com_probe, com_init, com_getc, com_putc },
#endif
	{ NULL }
};
struct consdev *cn_tab = constab;


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

/*
 * Copyright (c) 2004 Tom Cosgrove
 * Copyright (c) 1996-1999 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 "libsa.h"
#include "biosdev.h"
#include <sys/param.h>
#include <dev/cons.h>

extern int debug;

extern char *fs_name[];
extern int nfsname;
extern struct devsw netsw[];

extern char *bootmac;		/* Gets passed to kernel for network boot */

/* XXX use slot for 'rd' for 'hd' pseudo-device */
const char bdevs[][4] = {
	"wd", "", "fd", "", "sd", "st", "cd", "",
	"", "", "", "", "", "", "", "", "", "hd", ""
};
const int nbdevs = nitems(bdevs);

const char cdevs[][4] = {
	"cn", "", "", "", "", "", "", "",
	"com", "", "", "", "pc"
};
const int ncdevs = nitems(cdevs);

/* pass dev_t to the open routines */
int
devopen(struct open_file *f, const char *fname, char **file)
{
	struct devsw *dp = devsw;
	char *p;
	char *stripdev;
	int i, l;
	int rc = 1;

	*file = (char *)fname;

#ifdef DEBUG
	if (debug)
		printf("devopen(%s):", fname);
#endif

	/* Make sure we have a prefix, e.g. hd0a: or tftp:. */
	for (p = (char *)fname; *p != ':' && *p != '\0'; ) p++;
	if (*p != ':')
		return 1;
	stripdev = p + 1;

	l = p - fname;			/* Length of device prefix. */
	for (i = 0; i < nfsname; i++) {
		if ((fs_name[i] != NULL) &&
		    (strncmp(fname, fs_name[i], l) == 0)) {

			/* Force oopen() etc to use this filesystem. */
			f->f_ops = &file_system[i];
			f->f_dev = dp = &netsw[0];

			rc = (*dp->dv_open)(f, NULL);
			if (rc == 0)
				*file = stripdev;
			else
				f->f_dev = NULL;
#ifdef DEBUG
			if (debug)
				putchar('\n');
#endif
			return rc;
		}
	}

	/*
	 * Assume that any network filesystems would be caught by the
	 * code above, so that the next phase of devopen() is only for
	 * local devices.
	 *
	 * Clear bootmac, to signal that we loaded this file from a
	 * non-network device.
	 */
	bootmac = NULL;

	for (i = 0; i < ndevs && rc != 0; dp++, i++) {
#ifdef DEBUG
		if (debug)
			printf(" %s: ", dp->dv_name);
#endif
		if ((rc = (*dp->dv_open)(f, file)) == 0) {
			f->f_dev = dp;
			return 0;
		}
#ifdef DEBUG
		else if (debug)
			printf("%d", rc);
#endif

	}
#ifdef DEBUG
	if (debug)
		putchar('\n');
#endif

	if ((f->f_flags & F_NODEV) == 0)
		f->f_dev = dp;

	return rc;
}

void
devboot(dev_t bootdev, char *p)
{
	*p++ = 't';
	*p++ = 'f';
	*p++ = 't';
	*p++ = 'p';
	*p = '\0';
}

char ttyname_buf[8];

char *
ttyname(int fd)
{
	snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d",
	    cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev));

	return ttyname_buf;
}

dev_t
ttydev(char *name)
{
	int i, unit = -1;
	char *no = name + strlen(name) - 1;

	while (no >= name && *no >= '0' && *no <= '9')
		unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0';
	if (no < name || unit < 0)
		return NODEV;
	for (i = 0; i < ncdevs; i++)
		if (strncmp(name, cdevs[i], no - name + 1) == 0)
			return (makedev(i, unit));
	return NODEV;
}

int
cnspeed(dev_t dev, int sp)
{
	if (major(dev) == 8)	/* comN */
		return (comspeed(dev, sp));

	/* pc0 and anything else */
	return 9600;
}


code:
/*	$OpenBSD: open.c,v 1.1 2004/03/21 21:37:41 tom Exp $	*/
/*	$NetBSD: open.c,v 1.12 1996/09/30 16:01:21 ws Exp $	*/

/*-
 * Copyright (c) 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * The Mach Operating System project at Carnegie-Mellon University.
 *
 * 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.
 *
 *	@(#)open.c	8.1 (Berkeley) 6/11/93
 *
 *
 * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
 * All Rights Reserved.
 *
 * Author: Alessandro Forin
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <lib/libsa/stand.h>

struct open_file files[SOPEN_MAX];

/*
 *	File primitives proper
 */

int
#ifndef __INTERNAL_LIBSA_CREAD
open(const char *fname, int mode)
#else
oopen(const char *fname, int mode)
#endif
{
	struct open_file *f;
	int fd, i, error;
	char *file;

	/* find a free file descriptor */
	for (fd = 0, f = files; fd < SOPEN_MAX; fd++, f++)
		if (f->f_flags == 0)
			goto fnd;
	errno = EMFILE;
	return -1;
fnd:
	/*
	 * Try to open the device.
	 * Convert open mode (0,1,2) to F_READ, F_WRITE.
	 */
	f->f_flags = mode + 1;
	f->f_dev = (struct devsw *)0;
	f->f_ops = (struct fs_ops *)0;
	file = (char *)0;
	error = devopen(f, fname, &file);
	if (error ||
	    (((f->f_flags & F_NODEV) == 0) && f->f_dev == (struct devsw *)0))
		goto err;

	/* see if we opened a raw device; otherwise, 'file' is the file name. */
	if (file == (char *)0 || *file == '\0') {
		f->f_flags |= F_RAW;
		return fd;
	}

	/* Allow f->f_ops to be set by devopen routine. */
	if (f->f_ops != NULL) {
		error = f->f_ops->open(file, f);
		if (error == 0)
			return fd;
	}
	else {
		/* pass file name to the different filesystem open routines */
		for (i = 0; i < nfsys; i++) {
			/* convert mode (0,1,2) to FREAD, FWRITE. */
			error = (file_system[i].open)(file, f);
			if (error == 0) {
				f->f_ops = &file_system[i];
				return (fd);
			}
			if (error == ENOENT || error == ENOTDIR)
				break;
		}
	}
	if (error == 0)
		error = ENOENT;

	f->f_dev->dv_close(f);
err:
	f->f_flags = 0;
	errno = error;
	return -1;
}


code:
/*	$OpenBSD: pxe_udp.c,v 1.1 2014/11/19 20:09:58 miod Exp $	*/
/*	$NetBSD: net.c,v 1.14 1996/10/13 02:29:02 christos Exp $	*/

/*
 * Copyright (c) 1992 Regents of the University of California.
 * All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * 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 the University of
 *	California, Lawrence Berkeley Laboratory and its contributors.
 * 4. 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.
 *
 * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp  (LBL)
 */

#include <sys/param.h>
#include <sys/socket.h>

#include <net/if.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include <pxeboot.h>

/* Caller must leave room for ethernet, ip and udp headers in front!! */
ssize_t
sendudp(struct iodesc *d, void *pkt, size_t len)
{
	return pxesendudp(d, pkt, len);
}

/*
 * Receive a UDP packet and validate it is for us.
 * Caller leaves room for the headers (Ether, IP, UDP)
 */
ssize_t
readudp(struct iodesc *d, void *pkt, size_t len, time_t tleft)
{
	return pxereadudp(d, pkt, len, tleft);
}


code:
/*	$OpenBSD: srt0.S,v 1.3 2012/10/29 14:18:11 jsing Exp $	*/

/*
 * Copyright (c) 1997 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 REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
#include <machine/asm.h>
#include <assym.h>

#define BOOTSTACK 0xfffc

	.globl	_C_LABEL(end)
	.globl	_C_LABEL(edata)
	.globl	_C_LABEL(boot)
	.globl	_C_LABEL(_rtt)
	.globl	_C_LABEL(bios_bootdev)
	.globl	_ASM_LABEL(pmm_init)
	.globl	Gdtr

	.text
	.code16
	.globl	_start
_start:
#ifdef DEBUG
	movl	$0xb80a0, %ebx
	addr32 movl $0x07420742, (%ebx)
#endif

/* Clobbers %ax, maybe more */
#define	putc(c)		movb	$c, %al;	call	Lchr

	/*
	 * We are loaded by the PXE loader at location 0x7C00.  Like
	 * the standard /boot, we are linked to run at 0x40120 (load
	 * address 0x40000), so we relocate to there.
	 *
	 * From 0x7C00 to 0x40000 is 0x38400 (230400) bytes, so we don't
	 * have to worry about an overlapping copy until pxeboot is
	 * over 225 KB.
	 *
	 * PXE loads us with a stack that grows down from 0x80000 (512 KB).
	 * While it is unlikely that this will clash with our code that
	 * we're copying up, we create a temporary stack just below us
	 * before the relocate.  We also set the entire %esp register, to
	 * be on the safe side.
	 */
#define PXEBOOTADDR	0x7c00		/* Address where we are loaded by PXE */
	xorw	%ax, %ax
	movw	%ax, %ss		/* CPU disables interrupts till... */
	movl	$PXEBOOTADDR-4, %esp	/* after this instruction */

	pushl	%edx			/* Preserve the drive number. */

	movw	$(PXEBOOTADDR >> 4), %ax /* Reloc from %ds = 0x7c0. */
	movw	$(LINKADDR >> 4), %bx	 /* Reloc to %es = 0x4012. */

	movl	$_C_LABEL(end), %edx
	subl	$_C_LABEL(_start), %edx	/* How big are we? */

	/*
	 * Relocate in blocks that are a maximum of 32KB in size, incrementing
	 * the segment registers after each block. The 'rep; movsb' instruction
	 * uses %cx, which limits us to a maximum block size of 0xfff0, even
	 * though we can address the full 64KB within a single segment.
	 */
#define RELOC_BLOCK_SIZE 0x8000
reloc_loop:
	movl	%edx, %ecx
	jcxz	reloc_done
	cmpl	$RELOC_BLOCK_SIZE, %ecx
	jbe	reloc_notrunc
	movl	$RELOC_BLOCK_SIZE, %ecx
reloc_notrunc:
	subl	%ecx, %edx

	movw	%ax, %ds		/* Where we're coming from */
	xorw	%si, %si

	movw	%bx, %es		/* Where we're going to */
	xorw	%di, %di

	cld
	rep; movsb			/* Copy into place */

	addw	$(RELOC_BLOCK_SIZE >> 4), %ax
	addw	$(RELOC_BLOCK_SIZE >> 4), %bx

	jmp	reloc_loop

reloc_done:
	popl	%edx
	jmpl	$(LINKADDR >> 4), $(relocated-_start)	/* Now relocate */

relocated:
	/*
	 * In 16-bit mode, we have segment registers == 0x4012, and
	 * offsets work from here, with offset(_start) == 0.
	 *
	 * In 32-bit mode, we have a flat memory model, where
	 * offset(_start) == 0x40120.  This is how we're linked.
	 *
	 * Now transition to protected mode.
	 *
	 * First, initialise the global descriptor table.
	 */
	cli
	push	%cs
	pop	%ds
	addr32 data32 lgdt (Gdtr - LINKADDR)

	movl	%cr0, %eax
	orl	$CR0_PE, %eax
	data32 movl %eax, %cr0
	data32 ljmp $8, $1f		/* Seg sel 0x08 is flat 32-bit code */
1:
	.code32
	movl	$0x10, %eax		/* Seg sel 0x10 is flat 32-bit data */
	mov	%ax, %ds
	mov	%ax, %es
	mov	%ax, %fs
	mov	%ax, %gs
	mov	%ax, %ss
	movl	$BOOTSTACK, %esp
#ifdef DEBUG
	movl	$0xb8000, %ebx
	movl	$0x07420742, (%ebx)
#endif

	xorl	%edx, %edx
	movl	%edx, _C_LABEL(bios_bootdev)
	pushl	%edx			/* boot() takes this as a parameter */

#ifdef DEBUG
	movl	$0xb80a4, %ebx
	movl	$0x07520752, (%ebx)
#endif

	/* Zero .bss */
	xorl	%eax, %eax
	movl	$_C_LABEL(end), %ecx
	subl	$_C_LABEL(edata), %ecx
	movl	$_C_LABEL(edata), %edi
	cld
	rep;	stosb

	/* Set up an interrupt descriptor table for protected mode. */
	call	_ASM_LABEL(pmm_init)

	/* Set our program name ("PXEBOOT", not "BOOT"). */
	movl	$pxe_progname, %eax
	movl	%eax, progname

	/*
	 * Now call "main()".
	 *
	 * We run in flat 32-bit protected mode, with no address mapping.
	 */
#ifdef DEBUG
	movl	$0xb8004, %ebx
	movl	$0x07410741, (%ebx)
#endif
	call	_C_LABEL(boot)

	/* boot() should not return.  If it does, reset computer. */
	jmp	_C_LABEL(_rtt)

ENTRY(debugchar)
	pushl	%ebx
	movl	8(%esp), %ebx
	addl	%ebx, %ebx
	addl	$0xb8000, %ebx

	xorl	%eax, %eax
	movb	12(%esp), %al

	andl	$0xfffffffe, %ebx
	movb	%al, (%ebx)
	popl	%ebx
	ret

	.code16

/*
 * Write out value in %ax in hex
 */
hex_word:
	pushw	%ax
	mov	%ah, %al
	call	hex_byte
	popw	%ax
	/* fall thru */
/*
 * Write out value in %al in hex
 */
hex_byte:
	pushw	%ax
	shrb	$4, %al
	call	hex_nibble
	popw	%ax
	/* fall thru */

/* Write out nibble in %al */
hex_nibble:
	and	$0x0F, %al
	add	$'0', %al
	cmpb	$'9', %al
	jbe	Lchr
	addb	$'A'-'9'-1, %al
	/* fall thru to Lchr */
/*
 *	Lchr: write the character in %al to console
 */
Lchr:
	pushw	%bx
	movb	$0x0e, %ah
	xorw	%bx, %bx
	incw	%bx		/* movw $0x01, %bx */
	int	$0x10
	popw	%bx
	ret

pxe_progname:
	.asciz	"PXEBOOT"

	.end


code:
D/arm////
D/armv7////
D/conf////
D/cortex////
D/include////
D/mainbus////
D/sa11x0////
D/xscale////

path: sys/arch/arm/CVS/Entries


code: src/sys/arch/arm

path: sys/arch/arm/CVS/Repository


code: src/sys/arch/arm/arm

path: sys/arch/arm/arm/CVS/Repository


code:
/*	$OpenBSD: arm32_machdep.c,v 1.47 2015/01/12 16:33:31 deraadt Exp $	*/
/*	$NetBSD: arm32_machdep.c,v 1.42 2003/12/30 12:33:15 pk Exp $	*/

/*
 * Copyright (c) 1994-1998 Mark Brinicombe.
 * Copyright (c) 1994 Brini.
 * All rights reserved.
 *
 * This code is derived from software written for Brini by Mark Brinicombe
 *
 * 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 Mark Brinicombe
 *	for the NetBSD Project.
 * 4. The name of the company nor the name of the author may 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 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.
 *
 * Machine dependant functions for kernel setup
 *
 * Created      : 17/09/94
 * Updated	: 18/04/01 updated for new wscons
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/reboot.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/kernel.h>
#include <sys/mbuf.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/msg.h>
#include <sys/msgbuf.h>
#include <sys/device.h>
#include <sys/sysctl.h>

#include <uvm/uvm_extern.h>

#include <dev/cons.h>

#include <arm/machdep.h>
#include <machine/conf.h>

#ifdef CONF_HAVE_APM
#include "apm.h"
#else
#define NAPM	0
#endif
#include "rd.h"

struct vm_map *exec_map = NULL;
struct vm_map *phys_map = NULL;

extern int physmem;

struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
struct uvm_constraint_range *uvm_md_constraints[] = { NULL };

int cold = 1;

pv_addr_t kernelstack;

/* the following is used externally (sysctl_hw) */
char	machine[] = MACHINE;		/* from <machine/param.h> */

/* Statically defined CPU info. */
struct cpu_info cpu_info_primary;
struct cpu_info *cpu_info_list = &cpu_info_primary;

#ifdef MULTIPROCESSOR
/*
 * Array of CPU info structures.  Must be statically-allocated because
 * curproc, etc. are used early.
 */
struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary };
#endif

caddr_t	msgbufaddr;
extern paddr_t msgbufphys;

struct user *proc0paddr;

#ifdef APERTURE
#ifdef INSECURE
int allowaperture = 1;
#else
int allowaperture = 0;
#endif
#endif

#if defined(__zaurus__)
int lid_suspend = 1;
extern int xscale_maxspeed;
#endif

struct consdev *cn_tab;

/* Prototypes */

void data_abort_handler		(trapframe_t *frame);
void prefetch_abort_handler	(trapframe_t *frame);
extern void configure		(void);

/*
 * arm32_vector_init:
 *
 *	Initialize the vector page, and select whether or not to
 *	relocate the vectors.
 *
 *	NOTE: We expect the vector page to be mapped at its expected
 *	destination.
 */
void
arm32_vector_init(vaddr_t va, int which)
{
	extern unsigned int page0[], page0_data[];
	unsigned int *vectors = (unsigned int *) va;
	unsigned int *vectors_data = vectors + (page0_data - page0);
	int vec;

	/*
	 * Loop through the vectors we're taking over, and copy the
	 * vector's insn and data word.
	 */
	for (vec = 0; vec < ARM_NVEC; vec++) {
		if ((which & (1 << vec)) == 0) {
			/* Don't want to take over this vector. */
			continue;
		}
		vectors[vec] = page0[vec];
		vectors_data[vec] = page0_data[vec];
	}

	/* Now sync the vectors. */
	cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int));

	vector_page = va;

	if (va == ARM_VECTORS_HIGH) {
		/*
		 * Assume the MD caller knows what it's doing here, and
		 * really does want the vector page relocated.
		 *
		 * Note: This has to be done here (and not just in
		 * cpu_setup()) because the vector page needs to be
		 * accessible *before* cpu_startup() is called.
		 * Think ddb(9) ...
		 *
		 * NOTE: If the CPU control register is not readable,
		 * this will totally fail!  We'll just assume that
		 * any system that has high vector support has a
		 * readable CPU control register, for now.  If we
		 * ever encounter one that does not, we'll have to
		 * rethink this.
		 */
		cpu_control(CPU_CONTROL_VECRELOC, CPU_CONTROL_VECRELOC);
	}
}

/*
 * Debug function just to park the CPU
 */

void
halt()
{
	while (1)
		cpu_sleep(0);
}

/* Sync the discs and unmount the filesystems */

void
bootsync(int howto)
{
	static int bootsyncdone = 0;

	if (bootsyncdone)
		return;

	bootsyncdone = 1;

	/* Make sure we can still manage to do things */
	if (__get_cpsr() & I32_bit) {
		/*
		 * If we get here then boot has been called without RB_NOSYNC
		 * and interrupts were disabled. This means the boot() call
		 * did not come from a user process e.g. shutdown, but must
		 * have come from somewhere in the kernel.
		 */
		IRQenable;
		printf("Warning IRQ's disabled during boot()\n");
	}

	vfs_shutdown();

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

/*
 * void cpu_startup(void)
 *
 * Machine dependant startup code.
 *
 */
void
cpu_startup()
{
	u_int loop;
	paddr_t minaddr;
	paddr_t maxaddr;

	proc0paddr = (struct user *)kernelstack.pv_va;
	proc0.p_addr = proc0paddr;

	/* Set the cpu control register */
	cpu_setup();

	/* Lock down zero page */
	vector_page_setprot(PROT_READ | PROT_EXEC);

	/*
	 * Give pmap a chance to set up a few more things now the vm
	 * is initialised
	 */
	pmap_postinit();

	/*
	 * Allow per-board specific initialization
	 */
	board_startup();

	/*
	 * Initialize error message buffer (at end of core).
	 */

	/* msgbufphys was setup during the secondary boot strap */
	for (loop = 0; loop < atop(MSGBUFSIZE); ++loop)
		pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE,
		    msgbufphys + loop * PAGE_SIZE, PROT_READ | PROT_WRITE);
	pmap_update(pmap_kernel());
	initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE));

	/*
	 * Identify ourselves for the msgbuf (everything printed earlier will
	 * not be buffered).
	 */
	printf(version);

	printf("real mem  = %lu (%luMB)\n", ptoa(physmem),
	    ptoa(physmem)/1024/1024);

	/*
	 * Allocate a submap for exec arguments.  This map effectively
	 * limits the number of processes exec'ing at any time.
	 */
	minaddr = vm_map_min(kernel_map);
	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
				   16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);

	/*
	 * Allocate a submap for physio
	 */
	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
				   VM_PHYS_SIZE, 0, FALSE, NULL);

	/*
	 * Set up buffers, so they can be used to read disk labels.
	 */
	bufinit();

	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
	    ptoa(uvmexp.free)/1024/1024);

	curpcb = &proc0.p_addr->u_pcb;
	curpcb->pcb_flags = 0;
	curpcb->pcb_un.un_32.pcb32_und_sp = (u_int)proc0.p_addr +
	    USPACE_UNDEF_STACK_TOP;
	curpcb->pcb_un.un_32.pcb32_sp = (u_int)proc0.p_addr +
	    USPACE_SVC_STACK_TOP;
	pmap_set_pcb_pagedir(pmap_kernel(), curpcb);

        curpcb->pcb_tf = (struct trapframe *)curpcb->pcb_un.un_32.pcb32_sp - 1;
}

/*
 * 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;
{
#if NAPM > 0
	extern int cpu_apmwarn;
#endif

	/* all sysctl names at this level are terminal */
	if (namelen != 1)
		return (ENOTDIR);		/* overloaded */

	switch (name[0]) {
	case CPU_CONSDEV: {
		dev_t consdev;
		if (cn_tab != NULL)
			consdev = cn_tab->cn_dev;
		else
			consdev = NODEV;
		return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
			sizeof consdev));
	}

	case CPU_ALLOWAPERTURE:
#ifdef APERTURE
		if (securelevel > 0)
			return (sysctl_int_lower(oldp, oldlenp, newp, newlen,
			    &allowaperture));
		else
			return (sysctl_int(oldp, oldlenp, newp, newlen,
			    &allowaperture));
#else
		return (sysctl_rdint(oldp, oldlenp, newp, 0));
#endif

#if NAPM > 0
	case CPU_APMWARN:
		return (sysctl_int(oldp, oldlenp, newp, newlen, &cpu_apmwarn));
#endif
#if defined(__zaurus__)
	case CPU_LIDSUSPEND:
		return (sysctl_int(oldp, oldlenp, newp, newlen,
		    &lid_suspend));
	case CPU_MAXSPEED:
	{
		extern void pxa2x0_maxspeed(int *);
		int err = EINVAL;

		if (!newp && newlen == 0)
			return (sysctl_int(oldp, oldlenp, 0, 0,
			    &xscale_maxspeed));
		err = (sysctl_int(oldp, oldlenp, newp, newlen,
		    &xscale_maxspeed));
		pxa2x0_maxspeed(&xscale_maxspeed);
		return err;
	}
#endif

	default:
		return (EOPNOTSUPP);
	}
	/* NOTREACHED */
}


code:
/*	$OpenBSD: arm_machdep.c,v 1.3 2011/09/20 22:02:10 miod Exp $	*/
/*	$NetBSD: arm_machdep.c,v 1.7 2003/10/25 19:44:42 scw Exp $	*/

/*
 * Copyright (c) 2001 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 for the NetBSD Project by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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.
 */

/*
 * Copyright (c) 1994-1998 Mark Brinicombe.
 * Copyright (c) 1994 Brini.
 * All rights reserved.
 *
 * This code is derived from software written for Brini by Mark Brinicombe
 *
 * 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 Mark Brinicombe
 *	for the NetBSD Project.
 * 4. The name of the company nor the name of the author may 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 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 <sys/exec.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/pool.h>

#include <arm/cpufunc.h>

#include <machine/pcb.h>
#include <machine/vmparam.h>
#include <machine/bus.h>

static __inline struct trapframe *
process_frame(struct proc *p)
{

	return (p->p_addr->u_pcb.pcb_tf);
}

/*
 * The ARM architecture places the vector page at address 0.
 * Later ARM architecture versions, however, allow it to be
 * relocated to a high address (0xffff0000).  This is primarily
 * to support the Fast Context Switch Extension.
 *
 * This variable contains the address of the vector page.  It
 * defaults to 0; it only needs to be initialized if we enable
 * relocated vectors.
 */
vaddr_t	vector_page;

/*
 * Clear registers on exec
 */

void
setregs(struct proc *p, struct exec_package *pack, u_long stack,
    register_t *retval)
{
	struct trapframe *tf;

	tf = p->p_addr->u_pcb.pcb_tf;

	memset(tf, 0, sizeof(*tf));
/*	tf->tf_r0 = (u_int)p->p_proc->p_psstr; */
	tf->tf_usr_sp = stack;
	tf->tf_usr_lr = pack->ep_entry;
	tf->tf_svc_lr = 0x77777777;		/* Something we can see */
	tf->tf_pc = pack->ep_entry;
	tf->tf_spsr = PSR_USR32_MODE;

	p->p_addr->u_pcb.pcb_flags = 0;
	retval[1] = 0;
}


code:
/*	$OpenBSD: ast.c,v 1.14 2014/11/18 20:51:01 krw Exp $	*/
/*	$NetBSD: ast.c,v 1.6 2003/10/31 16:44:34 cl Exp $	*/

/*
 * Copyright (c) 1994,1995 Mark Brinicombe
 * 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 the RiscBSD team.
 * 4. The name of the company nor the name of the author may 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 OR CONTRIBUTERS 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.
 *
 * RiscBSD kernel project
 *
 * ast.c
 *
 * Code to handle ast's and returns to user mode
 *
 * Created      : 11/10/94
 */

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/acct.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/signal.h>
#include <sys/signalvar.h>
#include <sys/vmmeter.h>
#include <sys/syscall.h>
#include <sys/syscall_mi.h>

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

#include <arm/cpufunc.h>

#include <uvm/uvm_extern.h>

/*
 * Prototypes
 */
void ast(struct trapframe *);

int want_resched;
extern int astpending;

/*
 * Handle asynchronous system traps.
 * This is called from the irq handler to deliver signals
 * and switch processes if required.
 */

void
ast(struct trapframe *tf)
{
	struct proc *p = curproc;

	/* Interrupts were restored by exception_exit. */

	uvmexp.traps++;

#ifdef DEBUG
	if (p == NULL)
		panic("ast: no curproc!");
	if (&p->p_addr->u_pcb == 0)
		panic("ast: no pcb!");
#endif

	uvmexp.softs++;
	mi_ast(p, want_resched);
	userret(p);
}

/* End of ast.c */


code:
/*	$OpenBSD: bcopy_page.S,v 1.1 2004/02/01 05:09:48 drahn Exp $	*/
/*	$NetBSD: bcopy_page.S,v 1.7 2003/10/13 21:03:13 scw Exp $	*/

/*
 * Copyright (c) 1995 Scott Stevens
 * 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 Scott Stevens.
 * 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.
 *
 * RiscBSD kernel project
 *
 * bcopy_page.S
 *
 * page optimised bcopy and bzero routines
 *
 * Created      : 08/04/95
 */

#include <machine/asm.h>

#include "assym.h"

#ifndef __XSCALE__

/* #define BIG_LOOPS */

/*
 * bcopy_page(src, dest)
 *
 * Optimised copy page routine.
 *
 * On entry:
 *   r0 - src address
 *   r1 - dest address
 *
 * Requires:
 *   number of bytes per page (PAGE_SIZE) is a multiple of 512 (BIG_LOOPS), 128
 *   otherwise.
 */

#define	CHUNK_SIZE	32

#define	PREFETCH_FIRST_CHUNK	/* nothing */
#define	PREFETCH_NEXT_CHUNK	/* nothing */

#ifndef COPY_CHUNK
#define	COPY_CHUNK \
	PREFETCH_NEXT_CHUNK ; \
	ldmia	r0!, {r3-r8,ip,lr} ; \
	stmia	r1!, {r3-r8,ip,lr}
#endif /* ! COPY_CHUNK */

#ifndef SAVE_REGS
#define	SAVE_REGS	stmfd	sp!, {r4-r8, lr}
#define	RESTORE_REGS	ldmfd	sp!, {r4-r8, pc}
#endif

ENTRY(bcopy_page)
	PREFETCH_FIRST_CHUNK
	SAVE_REGS
#ifdef BIG_LOOPS
	mov	r2, #(PAGE_SIZE >> 9)
#else
	mov	r2, #(PAGE_SIZE >> 7)
#endif

1:
	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK

#ifdef BIG_LOOPS
	/* There is little point making the loop any larger; unless we are
	   running with the cache off, the load/store overheads will
	   completely dominate this loop.  */
	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK

	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK

	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK
	COPY_CHUNK
#endif
	subs	r2, r2, #1
	bne	1b

	RESTORE_REGS		/* ...and return. */

/*
 * bzero_page(dest)
 *
 * Optimised zero page routine.
 *
 * On entry:
 *   r0 - dest address
 *
 * Requires:
 *   number of bytes per page (PAGE_SIZE) is a multiple of 512 (BIG_LOOPS), 128
 *   otherwise
 */

ENTRY(bzero_page)
	stmfd	sp!, {r4-r8, lr}
#ifdef BIG_LOOPS
	mov	r2, #(PAGE_SIZE >> 9)
#else
	mov	r2, #(PAGE_SIZE >> 7)
#endif
	mov	r3, #0
	mov	r4, #0
	mov	r5, #0
	mov	r6, #0
	mov	r7, #0
	mov	r8, #0
	mov	ip, #0
	mov	lr, #0

1:
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}

#ifdef BIG_LOOPS
	/* There is little point making the loop any larger; unless we are
	   running with the cache off, the load/store overheads will
	   completely dominate this loop.  */
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}

	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}

	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}
	stmia	r0!, {r3-r8,ip,lr}

#endif

	subs	r2, r2, #1
	bne	1b

	ldmfd	sp!, {r4-r8, pc}

#else	/* __XSCALE__ */

/*
 * XSCALE version of bcopy_page
 */
ENTRY(bcopy_page)
	pld	[r0]
	stmfd	sp!, {r4, r5}
	mov	ip, #32
	ldr	r2, [r0], #0x04		/* 0x00 */
	ldr	r3, [r0], #0x04		/* 0x04 */
1:	pld	[r0, #0x18]		/* Prefetch 0x20 */
	ldr	r4, [r0], #0x04		/* 0x08 */
	ldr	r5, [r0], #0x04		/* 0x0c */
	strd	r2, [r1], #0x08
	ldr	r2, [r0], #0x04		/* 0x10 */
	ldr	r3, [r0], #0x04		/* 0x14 */
	strd	r4, [r1], #0x08
	ldr	r4, [r0], #0x04		/* 0x18 */
	ldr	r5, [r0], #0x04		/* 0x1c */
	strd	r2, [r1], #0x08
	ldr	r2, [r0], #0x04		/* 0x20 */
	ldr	r3, [r0], #0x04		/* 0x24 */
	pld	[r0, #0x18]		/* Prefetch 0x40 */
	strd	r4, [r1], #0x08
	ldr	r4, [r0], #0x04		/* 0x28 */
	ldr	r5, [r0], #0x04		/* 0x2c */
	strd	r2, [r1], #0x08
	ldr	r2, [r0], #0x04		/* 0x30 */
	ldr	r3, [r0], #0x04		/* 0x34 */
	strd	r4, [r1], #0x08
	ldr	r4, [r0], #0x04		/* 0x38 */
	ldr	r5, [r0], #0x04		/* 0x3c */
	strd	r2, [r1], #0x08
	ldr	r2, [r0], #0x04		/* 0x40 */
	ldr	r3, [r0], #0x04		/* 0x44 */
	pld	[r0, #0x18]		/* Prefetch 0x60 */
	strd	r4, [r1], #0x08
	ldr	r4, [r0], #0x04		/* 0x48 */
	ldr	r5, [r0], #0x04		/* 0x4c */
	strd	r2, [r1], #0x08
	ldr	r2, [r0], #0x04		/* 0x50 */
	ldr	r3, [r0], #0x04		/* 0x54 */
	strd	r4, [r1], #0x08
	ldr	r4, [r0], #0x04		/* 0x58 */
	ldr	r5, [r0], #0x04		/* 0x5c */
	strd	r2, [r1], #0x08
	ldr	r2, [r0], #0x04		/* 0x60 */
	ldr	r3, [r0], #0x04		/* 0x64 */
	pld	[r0, #0x18]		/* Prefetch 0x80 */
	strd	r4, [r1], #0x08
	ldr	r4, [r0], #0x04		/* 0x68 */
	ldr	r5, [r0], #0x04		/* 0x6c */
	strd	r2, [r1], #0x08
	ldr	r2, [r0], #0x04		/* 0x70 */
	ldr	r3, [r0], #0x04		/* 0x74 */
	strd	r4, [r1], #0x08
	ldr	r4, [r0], #0x04		/* 0x78 */
	ldr	r5, [r0], #0x04		/* 0x7c */
	strd	r2, [r1], #0x08
	subs	ip, ip, #0x01
	ldrgt	r2, [r0], #0x04		/* 0x80 */
	ldrgt	r3, [r0], #0x04		/* 0x84 */
	strd	r4, [r1], #0x08
	bgt	1b
	ldmfd	sp!, {r4, r5}
	mov	pc, lr

/*
 * XSCALE version of bzero_page
 */
ENTRY(bzero_page)
	mov	r1, #PAGE_SIZE
	mov	r2, #0
	mov	r3, #0
1:	strd	r2, [r0], #8		/* 32 */
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	strd	r2, [r0], #8		/* 64 */
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	strd	r2, [r0], #8		/* 96 */
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	strd	r2, [r0], #8		/* 128 */
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	strd	r2, [r0], #8
	subs	r1, r1, #128
	bne	1b
	mov	pc, lr
#endif	/* __XSCALE__ */