aboutsummaryrefslogtreecommitdiffstats
path: root/docs
Commit message (Expand)AuthorAgeFilesLines
* Fix docs build from a clean checkout, closes #2975Andy Boyett2008-01-071-1/+2
* Trivial patch to correct typos and spelling errors in OpenWRT documentation.\...Florian Fainelli2008-01-062-11/+11
* document the feeds systemFelix Fietkau2007-12-281-6/+8
* update build directory pathsFelix Fietkau2007-12-281-10/+10
* update target namesFelix Fietkau2007-12-281-5/+5
* remove some obsolete stuffFelix Fietkau2007-12-281-6/+0
* remove old 'Submitting patches' textFelix Fietkau2007-12-281-15/+0
* add SubmittingPatches document to docs/Felix Fietkau2007-12-283-1/+56
* START is no longer optional for /etc/rc.common based init scriptsFelix Fietkau2007-12-281-2/+1
* document Build/UninstallDevFelix Fietkau2007-12-281-0/+6
* document Build/InstallDevFelix Fietkau2007-12-281-0/+13
* add .gitignore for docs/Felix Fietkau2007-12-281-0/+15
* Allow specifying static IPv6 gateways (#2710)Florian Fainelli2007-11-161-0/+1
* Document the IPv6 connectivity with OpenWrt.Florian Fainelli2007-10-262-1/+47
* apply latex style patch posted on openwrt-devel@listsFelix Fietkau2007-09-292-7/+11
* Fix the option dns usages (#2174)Florian Fainelli2007-08-061-0/+2
* document config_foreach, close #2162Felix Fietkau2007-08-041-0/+19
* fix a few overfull hboxes, remove some redundant stuffFelix Fietkau2007-08-043-20/+12
* wifi docs: fix a few typos and inconsistencies, add examplesFelix Fietkau2007-08-041-14/+68
* Add some more documentationFlorian Fainelli2007-08-033-0/+65
* Fix a typo in the agmode selectionFlorian Fainelli2007-08-011-2/+2
* fix a typoFelix Fietkau2007-07-271-1/+1
* fix docs compile targetsFelix Fietkau2007-07-101-1/+3
* Add a paragraph on how to package kernel modulesFlorian Fainelli2007-03-241-1/+54
* Fix some mistakes and typosFlorian Fainelli2007-03-241-10/+9
* Updated content of wireless.tex, next version will have example configsNicholas DePetrillo2007-03-191-19/+99
* minor doc changesTim Yardley2007-03-021-8/+7
* add support for static routes - based on the patch from #1365Felix Fietkau2007-03-021-0/+18
* document MAKE_FLAGS and MAKE_VARSFelix Fietkau2007-02-261-0/+9
* document configure related build system changesFelix Fietkau2007-02-251-2/+14
* use NO_TRACE_MAKE for docs buildFelix Fietkau2007-02-251-4/+4
* change path to .prereq stampfileFelix Fietkau2007-02-251-2/+2
* add prereq checks for the documentation (#1400)Felix Fietkau2007-02-251-1/+18
* add documentation fixes from #1285Felix Fietkau2007-02-182-10/+10
* document make kernel_menuconfigFelix Fietkau2007-02-161-1/+9
* add html output for the documentation (using tex4ht)Felix Fietkau2007-01-252-6/+15
* Add a subsection on the bootloadersFlorian Fainelli2007-01-081-13/+65
* Add a "submitting patches" subsectionFlorian Fainelli2007-01-081-5/+15
* - Wrap long lines in the documentation, so that patches to the .tex files are...Felix Fietkau2007-01-073-71/+187
* Add some more documentation : how to add a new target to OpenWrt, howto repor...Florian Fainelli2007-01-055-26/+412
* fix b/g mode selection for madwifi, update documentationFelix Fietkau2007-01-041-4/+33
* some more build docsTim Yardley2006-11-262-7/+24
* some more build system documentationTim Yardley2006-11-261-40/+87
* some basic cleanup, stylistic change for config files, and slight fixesTim Yardley2006-11-066-196/+196
* add modified version of mbm's 'introduction to buildroot-ng' to the documenta...Felix Fietkau2006-10-163-4/+325
* add *.out to cleanup ruleFelix Fietkau2006-10-161-1/+1
* add documentation for /etc/config/wireless and improve formattingFelix Fietkau2006-10-164-36/+133
* add some documentation for the init scriptsFelix Fietkau2006-10-152-0/+62
* make table of contents clickableFelix Fietkau2006-10-131-1/+2
* make table of contents clickableFelix Fietkau2006-10-131-0/+1
61' href='#n561'>561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
/*
 *  Xen domain firmware emulation support
 *  Copyright (C) 2004 Hewlett-Packard Co.
 *       Dan Magenheimer (dan.magenheimer@hp.com)
 *
 * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
 *                    VA Linux Systems Japan K.K.
 *                    dom0 vp model support
 */

#include <xen/config.h>
#include <asm/system.h>
#include <asm/pgalloc.h>

#include <linux/efi.h>
#include <linux/sort.h>
#include <asm/io.h>
#include <asm/pal.h>
#include <asm/sal.h>
#include <asm/meminit.h>
#include <asm/fpswa.h>
#include <xen/version.h>
#include <xen/acpi.h>
#include <xen/errno.h>

#include <asm/dom_fw.h>
#include <asm/bundle.h>

#define ONE_MB (1UL << 20)

extern unsigned long running_on_sim;

#define FW_VENDOR "X\0e\0n\0/\0i\0a\0\066\0\064\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

#define MAKE_MD(typ, attr, start, end) 					\
	do {								\
		md = tables->efi_memmap + i++;				\
		md->type = typ;						\
		md->pad = 0;						\
		md->phys_addr = start;					\
		md->virt_addr = 0;					\
		md->num_pages = (end - start) >> EFI_PAGE_SHIFT;	\
		md->attribute = attr;					\
	} while (0)

#define EFI_HYPERCALL_PATCH(tgt, call)					\
	do {								\
		dom_efi_hypercall_patch(d, FW_HYPERCALL_##call##_PADDR,	\
		                 FW_HYPERCALL_##call, hypercalls_imva);	\
		/* Descriptor address.  */                              \
		tables->efi_runtime.tgt =                               \
		                    FW_FIELD_MPA(func_ptrs) + 8 * pfn;  \
		/* Descriptor.  */                                      \
		tables->func_ptrs[pfn++] = FW_HYPERCALL_##call##_PADDR;	\
		tables->func_ptrs[pfn++] = 0;                     	\
	} while (0)

/* allocate a page for fw
 * guest_setup() @ libxc/xc_linux_build.c does for domU
 */
static inline void
assign_new_domain_page_if_dom0(struct domain *d, unsigned long mpaddr)
{
        if (d == dom0)
            assign_new_domain0_page(d, mpaddr);
}

/**************************************************************************
Hypercall bundle creation
**************************************************************************/

static void
build_hypercall_bundle(u64 *imva, u64 brkimm, u64 hypnum, u64 ret)
{
	INST64_A5 slot0;
	INST64_I19 slot1;
	INST64_B4 slot2;
	IA64_BUNDLE bundle;

	// slot1: mov r2 = hypnum (low 20 bits)
	slot0.inst = 0;
	slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9;
	slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7;
	slot0.imm5c = hypnum >> 16; slot0.s = 0;
	// slot1: break brkimm
	slot1.inst = 0;
	slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0;
	slot1.imm20 = brkimm; slot1.i = brkimm >> 20;
	// if ret slot2:  br.ret.sptk.many rp
	// else   slot2:  br.cond.sptk.many rp
	slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0;
	slot2.wh = 0; slot2.d = 0; slot2.major = 0x0;
	if (ret) {
		slot2.btype = 4; slot2.x6 = 0x21;
	}
	else {
		slot2.btype = 0; slot2.x6 = 0x20;
	}
	
	bundle.i64[0] = 0; bundle.i64[1] = 0;
	bundle.template = 0x11;
	bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst;
	bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18;
	
	imva[0] = bundle.i64[0]; imva[1] = bundle.i64[1];
	ia64_fc(imva);
	ia64_fc(imva + 1);
}

static void
build_pal_hypercall_bundles(u64 *imva, u64 brkimm, u64 hypnum)
{
	extern unsigned long pal_call_stub[];
	IA64_BUNDLE bundle;
	INST64_A5 slot_a5;
	INST64_M37 slot_m37;

	/* The source of the hypercall stub is the pal_call_stub function
	   defined in xenasm.S.  */

	/* Copy the first bundle and patch the hypercall number.  */
	bundle.i64[0] = pal_call_stub[0];
	bundle.i64[1] = pal_call_stub[1];
	slot_a5.inst = bundle.slot0;
	slot_a5.imm7b = hypnum;
	slot_a5.imm9d = hypnum >> 7;
	slot_a5.imm5c = hypnum >> 16;
	bundle.slot0 = slot_a5.inst;
	imva[0] = bundle.i64[0];
	imva[1] = bundle.i64[1];
	ia64_fc(imva);
	ia64_fc(imva + 1);
	
	/* Copy the second bundle and patch the hypercall vector.  */
	bundle.i64[0] = pal_call_stub[2];
	bundle.i64[1] = pal_call_stub[3];
	slot_m37.inst = bundle.slot0;
	slot_m37.imm20a = brkimm;
	slot_m37.i = brkimm >> 20;
	bundle.slot0 = slot_m37.inst;
	imva[2] = bundle.i64[0];
	imva[3] = bundle.i64[1];
	ia64_fc(imva + 2);
	ia64_fc(imva + 3);
}

// builds a hypercall bundle at domain physical address
static void
dom_fpswa_hypercall_patch(struct domain *d, unsigned long imva)
{
	unsigned long *entry_imva, *patch_imva;
	const unsigned long entry_paddr = FW_HYPERCALL_FPSWA_ENTRY_PADDR;
	const unsigned long patch_paddr = FW_HYPERCALL_FPSWA_PATCH_PADDR;

	entry_imva = (unsigned long *)(imva + entry_paddr -
	                               FW_HYPERCALL_BASE_PADDR);
	patch_imva = (unsigned long *)(imva + patch_paddr -
	                               FW_HYPERCALL_BASE_PADDR);

	/* Descriptor.  */
	*entry_imva++ = patch_paddr;
	*entry_imva   = 0;

	build_hypercall_bundle(patch_imva, d->arch.breakimm,
	                       FW_HYPERCALL_FPSWA, 1);
}

// builds a hypercall bundle at domain physical address
static void
dom_efi_hypercall_patch(struct domain *d, unsigned long paddr,
                        unsigned long hypercall, unsigned long imva)
{
	build_hypercall_bundle((u64 *)(imva + paddr - FW_HYPERCALL_BASE_PADDR),
	                       d->arch.breakimm, hypercall, 1);
}

// builds a hypercall bundle at domain physical address
static void
dom_fw_hypercall_patch(struct domain *d, unsigned long paddr,
                       unsigned long hypercall,unsigned long ret,
                       unsigned long imva)
{
	build_hypercall_bundle((u64 *)(imva + paddr - FW_HYPERCALL_BASE_PADDR),
	                       d->arch.breakimm, hypercall, ret);
}

static void
dom_fw_pal_hypercall_patch(struct domain *d, unsigned long paddr,
                           unsigned long imva)
{
	build_pal_hypercall_bundles((u64*)(imva + paddr -
	                            FW_HYPERCALL_BASE_PADDR),
	                            d->arch.breakimm, FW_HYPERCALL_PAL_CALL);
}

static inline void
print_md(efi_memory_desc_t *md)
{
	u64 size;
	
	printk("dom mem: type=%2u, attr=0x%016lx, range=[0x%016lx-0x%016lx) ",
	       md->type, md->attribute, md->phys_addr,
	       md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT));

	size = md->num_pages << EFI_PAGE_SHIFT;
	if (size > ONE_MB)
		printk ("(%luMB)\n", size >> 20);
	else
		printk ("(%luKB)\n", size >> 10);
}

static u32 lsapic_nbr;

/* Modify lsapic table.  Provides LPs.  */
static int 
acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end)
{
	struct acpi_table_lsapic *lsapic;
	int enable;

	lsapic = (struct acpi_table_lsapic *) header;
	if (!lsapic)
		return -EINVAL;

	if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
		enable = 1;
	else
		enable = 0;
	if (lsapic->flags.enabled && enable) {
		printk("enable lsapic entry: 0x%lx\n", (u64)lsapic);
		lsapic->id = lsapic_nbr;
		lsapic->eid = 0;
		lsapic_nbr++;
	} else if (lsapic->flags.enabled) {
		printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic);
		lsapic->flags.enabled = 0;
		lsapic->id = 0;
		lsapic->eid = 0;
	}
	return 0;
}

static int __init
acpi_patch_plat_int_src (
	acpi_table_entry_header *header, const unsigned long end)
{
	struct acpi_table_plat_int_src *plintsrc;

	plintsrc = (struct acpi_table_plat_int_src *)header;
	if (!plintsrc)
		return -EINVAL;

	if (plintsrc->type == ACPI_INTERRUPT_CPEI) {
		printk("ACPI_INTERRUPT_CPEI disabled for Domain0\n");
		plintsrc->type = -1;
	}
	return 0;
}

static u8
generate_acpi_checksum(void *tbl, unsigned long len)
{
	u8 *ptr, sum = 0;

	for (ptr = tbl; len > 0 ; len--, ptr++)
		sum += *ptr;

	return 0 - sum;
}

static int
acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size)
{
	struct acpi_table_madt* acpi_madt;

	if (!phys_addr || !size)
		return -EINVAL;

	acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
	acpi_madt->header.checksum = 0;
	acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);

	return 0;
}

/* base is physical address of acpi table */
static void touch_acpi_table(void)
{
	lsapic_nbr = 0;
	if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
		printk("Error parsing MADT - no LAPIC entries\n");
	if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC,
	                          acpi_patch_plat_int_src, 0) < 0)
		printk("Error parsing MADT - no PLAT_INT_SRC entries\n");

	acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);

	return;
}

struct fake_acpi_tables {
	struct acpi20_table_rsdp rsdp;
	struct xsdt_descriptor_rev2 xsdt;
	u64 madt_ptr;
	struct fadt_descriptor_rev2 fadt;
	struct facs_descriptor_rev2 facs;
	struct acpi_table_header dsdt;
	u8 aml[8 + 11 * MAX_VIRT_CPUS];
	struct acpi_table_madt madt;
	struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS];
	u8 pm1a_evt_blk[4];
	u8 pm1a_cnt_blk[1];
	u8 pm_tmr_blk[4];
};
#define ACPI_TABLE_MPA(field) \
  FW_ACPI_BASE_PADDR + offsetof(struct fake_acpi_tables, field);

/* Create enough of an ACPI structure to make the guest OS ACPI happy. */
static void
dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
{
	struct acpi20_table_rsdp *rsdp = &tables->rsdp;
	struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt;
	struct fadt_descriptor_rev2 *fadt = &tables->fadt;
	struct facs_descriptor_rev2 *facs = &tables->facs;
	struct acpi_table_header *dsdt = &tables->dsdt;
	struct acpi_table_madt *madt = &tables->madt;
	struct acpi_table_lsapic *lsapic = tables->lsapic;
	int i;
	int aml_len;
	int nbr_cpus;

	memset(tables, 0, sizeof(struct fake_acpi_tables));

	/* setup XSDT (64bit version of RSDT) */
	memcpy(xsdt->signature, XSDT_SIG, sizeof(xsdt->signature));
	/* XSDT points to both the FADT and the MADT, so add one entry */
	xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(u64);
	xsdt->revision = 1;
	memcpy(xsdt->oem_id, "XEN", 3);
	memcpy(xsdt->oem_table_id, "Xen/ia64", 8);
	memcpy(xsdt->asl_compiler_id, "XEN", 3);
	xsdt->asl_compiler_revision = (xen_major_version() << 16) |
		xen_minor_version();

	xsdt->table_offset_entry[0] = ACPI_TABLE_MPA(fadt);
	tables->madt_ptr = ACPI_TABLE_MPA(madt);

	xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length);

	/* setup FADT */
	memcpy(fadt->signature, FADT_SIG, sizeof(fadt->signature));
	fadt->length = sizeof(struct fadt_descriptor_rev2);
	fadt->revision = FADT2_REVISION_ID;
	memcpy(fadt->oem_id, "XEN", 3);
	memcpy(fadt->oem_table_id, "Xen/ia64", 8);
	memcpy(fadt->asl_compiler_id, "XEN", 3);
	fadt->asl_compiler_revision = (xen_major_version() << 16) |
		xen_minor_version();

	memcpy(facs->signature, FACS_SIG, sizeof(facs->signature));
	facs->version = 1;
	facs->length = sizeof(struct facs_descriptor_rev2);

	fadt->xfirmware_ctrl = ACPI_TABLE_MPA(facs);
	fadt->Xdsdt = ACPI_TABLE_MPA(dsdt);

	/*
	 * All of the below FADT entries are filled it to prevent warnings
	 * from sanity checks in the ACPI CA.  Emulate required ACPI hardware
	 * registers in system memory.
	 */
	fadt->pm1_evt_len = 4;
	fadt->xpm1a_evt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
	fadt->xpm1a_evt_blk.register_bit_width = 8;
	fadt->xpm1a_evt_blk.address = ACPI_TABLE_MPA(pm1a_evt_blk);
	fadt->pm1_cnt_len = 1;
	fadt->xpm1a_cnt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
	fadt->xpm1a_cnt_blk.register_bit_width = 8;
	fadt->xpm1a_cnt_blk.address = ACPI_TABLE_MPA(pm1a_cnt_blk);
	fadt->pm_tm_len = 4;
	fadt->xpm_tmr_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
	fadt->xpm_tmr_blk.register_bit_width = 8;
	fadt->xpm_tmr_blk.address = ACPI_TABLE_MPA(pm_tmr_blk);

	fadt->checksum = generate_acpi_checksum(fadt, fadt->length);

	/* setup RSDP */
	memcpy(rsdp->signature, RSDP_SIG, strlen(RSDP_SIG));
	memcpy(rsdp->oem_id, "XEN", 3);
	rsdp->revision = 2; /* ACPI 2.0 includes XSDT */
	rsdp->length = sizeof(struct acpi20_table_rsdp);
	rsdp->xsdt_address = ACPI_TABLE_MPA(xsdt);

	rsdp->checksum = generate_acpi_checksum(rsdp,
	                                        ACPI_RSDP_CHECKSUM_LENGTH);
	rsdp->ext_checksum = generate_acpi_checksum(rsdp, rsdp->length);

	/* setup DSDT with trivial namespace. */ 
	memcpy(dsdt->signature, DSDT_SIG, strlen(DSDT_SIG));
	dsdt->revision = 1;
	memcpy(dsdt->oem_id, "XEN", 3);
	memcpy(dsdt->oem_table_id, "Xen/ia64", 8);
	memcpy(dsdt->asl_compiler_id, "XEN", 3);
	dsdt->asl_compiler_revision = (xen_major_version() << 16) |
		xen_minor_version();

	/* Trivial namespace, avoids ACPI CA complaints */
	tables->aml[0] = 0x10; /* Scope */
	tables->aml[1] = 0x40; /* length/offset to next object (patched) */
	tables->aml[2] = 0x00;
	memcpy(&tables->aml[3], "_SB_", 4);

	/* The processor object isn't absolutely necessary, revist for SMP */
	aml_len = 7;
	for (i = 0; i < 3; i++) {
		unsigned char *p = tables->aml + aml_len;
		p[0] = 0x5b; /* processor object */
		p[1] = 0x83;
		p[2] = 0x0b; /* next */
		p[3] = 'C';
		p[4] = 'P';
		snprintf ((char *)p + 5, 3, "%02x", i);
		if (i < 16)
			p[5] = 'U';
		p[7] = i;	/* acpi_id */
		p[8] = 0;	/* pblk_addr */
		p[9] = 0;
		p[10] = 0;
		p[11] = 0;
		p[12] = 0;	/* pblk_len */
		aml_len += 13;
	}
	tables->aml[1] = 0x40 + ((aml_len - 1) & 0x0f);
	tables->aml[2] = (aml_len - 1) >> 4;
	dsdt->length = sizeof(struct acpi_table_header) + aml_len;
	dsdt->checksum = generate_acpi_checksum(dsdt, dsdt->length);

	/* setup MADT */
	memcpy(madt->header.signature, APIC_SIG, sizeof(madt->header.signature));
	madt->header.revision = 2;
	memcpy(madt->header.oem_id, "XEN", 3);
	memcpy(madt->header.oem_table_id, "Xen/ia64", 8);
	memcpy(madt->header.asl_compiler_id, "XEN", 3);
	madt->header.asl_compiler_revision = (xen_major_version() << 16) |
		xen_minor_version();

	/* An LSAPIC entry describes a CPU.  */
	nbr_cpus = 0;
	for (i = 0; i < MAX_VIRT_CPUS; i++) {
		lsapic[i].header.type = ACPI_MADT_LSAPIC;
		lsapic[i].header.length = sizeof(struct acpi_table_lsapic);
		lsapic[i].acpi_id = i;
		lsapic[i].id = i;
		lsapic[i].eid = 0;
		if (d->vcpu[i] != NULL) {