mirror of
				https://gitlab.com/qemu-project/qboot.git
				synced 2024-02-13 08:33:40 +08:00 
			
		
		
		
	implement mptable generation
This is specially useful for machines lacking ACPI. Signed-off-by: Sergio Lopez <slp@redhat.com>
This commit is contained in:
		 Sergio Lopez
					Sergio Lopez
				
			
				
					committed by
					
						 Paolo Bonzini
						Paolo Bonzini
					
				
			
			
				
	
			
			
			 Paolo Bonzini
						Paolo Bonzini
					
				
			
						parent
						
							947bade344
						
					
				
				
					commit
					e5b140b91b
				
			
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,5 +1,6 @@ | ||||
| obj-y = code16.o entry.o main.o string.o printf.o cstart.o fw_cfg.o | ||||
| obj-y += linuxboot.o malloc.o pflash.o tables.o hwsetup.o pci.o code32seg.o | ||||
| obj-y += mptable.o | ||||
|  | ||||
| all-y = bios.bin | ||||
| all: $(all-y) | ||||
|  | ||||
| @ -66,6 +66,7 @@ extern uint32_t pic_base(void); | ||||
| extern void setup_pci(void); | ||||
| extern bool setup_hw(void); | ||||
| extern bool setup_mmconfig(void); | ||||
| extern void setup_mptable(void); | ||||
| extern void extract_acpi(void); | ||||
| extern void boot_from_fwcfg(void); | ||||
|  | ||||
|  | ||||
							
								
								
									
										182
									
								
								include/mpspec_def.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								include/mpspec_def.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,182 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0 */ | ||||
| #ifndef _ASM_X86_MPSPEC_DEF_H | ||||
| #define _ASM_X86_MPSPEC_DEF_H | ||||
|  | ||||
| /* | ||||
|  * Structure definitions for SMP machines following the | ||||
|  * Intel Multiprocessing Specification 1.1 and 1.4. | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * This tag identifies where the SMP configuration | ||||
|  * information is. | ||||
|  */ | ||||
|  | ||||
| #define SMP_MAGIC_IDENT	(('_'<<24) | ('P'<<16) | ('M'<<8) | '_') | ||||
|  | ||||
| #ifdef CONFIG_X86_32 | ||||
| # define MAX_MPC_ENTRY 1024 | ||||
| #endif | ||||
|  | ||||
| /* Intel MP Floating Pointer Structure */ | ||||
| struct mpf_intel { | ||||
| 	char signature[4];		/* "_MP_"			*/ | ||||
| 	unsigned int physptr;		/* Configuration table address	*/ | ||||
| 	unsigned char length;		/* Our length (paragraphs)	*/ | ||||
| 	unsigned char specification;	/* Specification version	*/ | ||||
| 	unsigned char checksum;		/* Checksum (makes sum 0)	*/ | ||||
| 	unsigned char feature1;		/* Standard or configuration ?	*/ | ||||
| 	unsigned char feature2;		/* Bit7 set for IMCR|PIC	*/ | ||||
| 	unsigned char feature3;		/* Unused (0)			*/ | ||||
| 	unsigned char feature4;		/* Unused (0)			*/ | ||||
| 	unsigned char feature5;		/* Unused (0)			*/ | ||||
| }; | ||||
|  | ||||
| #define MPC_SIGNATURE "PCMP" | ||||
|  | ||||
| struct mpc_table { | ||||
| 	char signature[4]; | ||||
| 	unsigned short length;		/* Size of table */ | ||||
| 	char spec;			/* 0x01 */ | ||||
| 	char checksum; | ||||
| 	char oem[8]; | ||||
| 	char productid[12]; | ||||
| 	unsigned int oemptr;		/* 0 if not present */ | ||||
| 	unsigned short oemsize;		/* 0 if not present */ | ||||
| 	unsigned short oemcount; | ||||
| 	unsigned int lapic;		/* APIC address */ | ||||
| 	unsigned int reserved; | ||||
| }; | ||||
|  | ||||
| /* Followed by entries */ | ||||
|  | ||||
| #define	MP_PROCESSOR		0 | ||||
| #define	MP_BUS			1 | ||||
| #define	MP_IOAPIC		2 | ||||
| #define	MP_INTSRC		3 | ||||
| #define	MP_LINTSRC		4 | ||||
| /* Used by IBM NUMA-Q to describe node locality */ | ||||
| #define	MP_TRANSLATION		192 | ||||
|  | ||||
| #define CPU_ENABLED		1	/* Processor is available */ | ||||
| #define CPU_BOOTPROCESSOR	2	/* Processor is the boot CPU */ | ||||
|  | ||||
| #define CPU_STEPPING_MASK	0x000F | ||||
| #define CPU_MODEL_MASK		0x00F0 | ||||
| #define CPU_FAMILY_MASK		0x0F00 | ||||
|  | ||||
| struct mpc_cpu { | ||||
| 	unsigned char type; | ||||
| 	unsigned char apicid;		/* Local APIC number */ | ||||
| 	unsigned char apicver;		/* Its versions */ | ||||
| 	unsigned char cpuflag; | ||||
| 	unsigned int cpufeature; | ||||
| 	unsigned int featureflag;	/* CPUID feature value */ | ||||
| 	unsigned int reserved[2]; | ||||
| }; | ||||
|  | ||||
| struct mpc_bus { | ||||
| 	unsigned char type; | ||||
| 	unsigned char busid; | ||||
| 	unsigned char bustype[6]; | ||||
| }; | ||||
|  | ||||
| /* List of Bus Type string values, Intel MP Spec. */ | ||||
| #define BUSTYPE_EISA	"EISA" | ||||
| #define BUSTYPE_ISA	"ISA" | ||||
| #define BUSTYPE_INTERN	"INTERN"	/* Internal BUS */ | ||||
| #define BUSTYPE_MCA	"MCA"		/* Obsolete */ | ||||
| #define BUSTYPE_VL	"VL"		/* Local bus */ | ||||
| #define BUSTYPE_PCI	"PCI" | ||||
| #define BUSTYPE_PCMCIA	"PCMCIA" | ||||
| #define BUSTYPE_CBUS	"CBUS" | ||||
| #define BUSTYPE_CBUSII	"CBUSII" | ||||
| #define BUSTYPE_FUTURE	"FUTURE" | ||||
| #define BUSTYPE_MBI	"MBI" | ||||
| #define BUSTYPE_MBII	"MBII" | ||||
| #define BUSTYPE_MPI	"MPI" | ||||
| #define BUSTYPE_MPSA	"MPSA" | ||||
| #define BUSTYPE_NUBUS	"NUBUS" | ||||
| #define BUSTYPE_TC	"TC" | ||||
| #define BUSTYPE_VME	"VME" | ||||
| #define BUSTYPE_XPRESS	"XPRESS" | ||||
|  | ||||
| #define MPC_APIC_USABLE		0x01 | ||||
|  | ||||
| struct mpc_ioapic { | ||||
| 	unsigned char type; | ||||
| 	unsigned char apicid; | ||||
| 	unsigned char apicver; | ||||
| 	unsigned char flags; | ||||
| 	unsigned int apicaddr; | ||||
| }; | ||||
|  | ||||
| struct mpc_intsrc { | ||||
| 	unsigned char type; | ||||
| 	unsigned char irqtype; | ||||
| 	unsigned short irqflag; | ||||
| 	unsigned char srcbus; | ||||
| 	unsigned char srcbusirq; | ||||
| 	unsigned char dstapic; | ||||
| 	unsigned char dstirq; | ||||
| }; | ||||
|  | ||||
| enum mp_irq_source_types { | ||||
| 	mp_INT = 0, | ||||
| 	mp_NMI = 1, | ||||
| 	mp_SMI = 2, | ||||
| 	mp_ExtINT = 3 | ||||
| }; | ||||
|  | ||||
| #define MP_IRQPOL_DEFAULT	0x0 | ||||
| #define MP_IRQPOL_ACTIVE_HIGH	0x1 | ||||
| #define MP_IRQPOL_RESERVED	0x2 | ||||
| #define MP_IRQPOL_ACTIVE_LOW	0x3 | ||||
| #define MP_IRQPOL_MASK		0x3 | ||||
|  | ||||
| #define MP_IRQTRIG_DEFAULT	0x0 | ||||
| #define MP_IRQTRIG_EDGE		0x4 | ||||
| #define MP_IRQTRIG_RESERVED	0x8 | ||||
| #define MP_IRQTRIG_LEVEL	0xc | ||||
| #define MP_IRQTRIG_MASK		0xc | ||||
|  | ||||
| #define MP_APIC_ALL	0xFF | ||||
|  | ||||
| struct mpc_lintsrc { | ||||
| 	unsigned char type; | ||||
| 	unsigned char irqtype; | ||||
| 	unsigned short irqflag; | ||||
| 	unsigned char srcbusid; | ||||
| 	unsigned char srcbusirq; | ||||
| 	unsigned char destapic; | ||||
| 	unsigned char destapiclint; | ||||
| }; | ||||
|  | ||||
| #define MPC_OEM_SIGNATURE "_OEM" | ||||
|  | ||||
| struct mpc_oemtable { | ||||
| 	char signature[4]; | ||||
| 	unsigned short length;		/* Size of table */ | ||||
| 	char  rev;			/* 0x01 */ | ||||
| 	char  checksum; | ||||
| 	char  mpc[8]; | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  *	Default configurations | ||||
|  * | ||||
|  *	1	2 CPU ISA 82489DX | ||||
|  *	2	2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining | ||||
|  *	3	2 CPU EISA 82489DX | ||||
|  *	4	2 CPU MCA 82489DX | ||||
|  *	5	2 CPU ISA+PCI | ||||
|  *	6	2 CPU EISA+PCI | ||||
|  *	7	2 CPU MCA+PCI | ||||
|  */ | ||||
|  | ||||
| enum mp_bustype { | ||||
| 	MP_BUS_ISA = 1, | ||||
| 	MP_BUS_EISA, | ||||
| 	MP_BUS_PCI, | ||||
| }; | ||||
| #endif /* _ASM_X86_MPSPEC_DEF_H */ | ||||
							
								
								
									
										1
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								main.c
									
									
									
									
									
								
							| @ -98,6 +98,7 @@ int __attribute__ ((section (".text.startup"))) main(void) | ||||
| 	fw_cfg_setup(); | ||||
| 	extract_acpi(); | ||||
| 	extract_e820(); | ||||
| 	setup_mptable(); | ||||
| 	// extract_smbios(); | ||||
| 	boot_from_fwcfg(); | ||||
| 	panic(); | ||||
|  | ||||
							
								
								
									
										186
									
								
								mptable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								mptable.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,186 @@ | ||||
| #include "include/string.h" | ||||
| #include "bios.h" | ||||
| #include "fw_cfg.h" | ||||
| #include "include/mpspec_def.h" | ||||
|  | ||||
| #define MPTABLE_START    0x9fc00 | ||||
| #define APIC_VERSION     0x14 | ||||
| #define MPC_SPEC         0x4 | ||||
|  | ||||
| #define MP_IRQDIR_DEFAULT 0 | ||||
| #define MP_IRQDIR_HIGH    1 | ||||
| #define MP_IRQDIR_LOW     3 | ||||
|  | ||||
| static const char MPC_OEM[]        = "QBOOT   "; | ||||
| static const char MPC_PRODUCT_ID[] = "000000000000"; | ||||
| static const char BUS_TYPE_ISA[]   = "ISA   "; | ||||
|  | ||||
| #define IO_APIC_DEFAULT_PHYS_BASE 0xfec00000 | ||||
| #define APIC_DEFAULT_PHYS_BASE    0xfee00000 | ||||
| #define APIC_VERSION              0x14 | ||||
|  | ||||
| static int mptable_checksum(char *buf, int size) | ||||
| { | ||||
| 	int i; | ||||
| 	int sum = 0; | ||||
|  | ||||
| 	for (i = 0; i < size; i++) { | ||||
| 		sum += buf[i]; | ||||
| 	} | ||||
|  | ||||
| 	return sum; | ||||
| } | ||||
|  | ||||
| static void mptable_get_cpuid(int *signature, int *features) | ||||
| { | ||||
| 	int ebx, ecx; | ||||
|  | ||||
| 	asm("cpuid" | ||||
| 	    : "=a" (*signature), "=b" (ebx), "=c" (ecx), "=d" (*features) | ||||
| 	    : "0" (1)); | ||||
| } | ||||
|  | ||||
| void setup_mptable(void) | ||||
| { | ||||
| 	struct mpf_intel *mpf; | ||||
| 	struct mpc_table *table; | ||||
| 	struct mpc_cpu *cpu; | ||||
| 	struct mpc_bus *bus; | ||||
| 	struct mpc_ioapic *ioapic; | ||||
| 	struct mpc_intsrc *intsrc; | ||||
| 	struct mpc_lintsrc *lintsrc; | ||||
| 	const char mpc_signature[] = MPC_SIGNATURE; | ||||
| 	const char smp_magic_ident[] = "_MP_"; | ||||
| 	int cpuid_stepping, cpuid_features; | ||||
| 	int irq0_override = 0; | ||||
| 	int checksum = 0; | ||||
| 	int offset = 0; | ||||
| 	int num_cpus; | ||||
| 	int ssize; | ||||
| 	int i; | ||||
|  | ||||
| 	ssize = sizeof(struct mpf_intel); | ||||
|  | ||||
| 	mpf = (struct mpf_intel *) MPTABLE_START; | ||||
| 	memset(mpf, 0, ssize); | ||||
| 	memcpy(mpf->signature, smp_magic_ident, sizeof(smp_magic_ident) - 1); | ||||
| 	mpf->length = 1; | ||||
| 	mpf->specification = 4; | ||||
| 	mpf->physptr = MPTABLE_START + ssize; | ||||
| 	mpf->checksum -= mptable_checksum((char *) mpf, ssize); | ||||
|  | ||||
| 	offset += ssize; | ||||
| 	ssize = sizeof(struct mpc_table); | ||||
|  | ||||
| 	table = (struct mpc_table *) (MPTABLE_START + offset); | ||||
| 	memset(table, 0, ssize); | ||||
| 	memcpy(table->signature, mpc_signature, sizeof(mpc_signature) - 1); | ||||
| 	table->spec = MPC_SPEC; | ||||
| 	memcpy(table->oem, MPC_OEM, sizeof(MPC_OEM) - 1); | ||||
| 	memcpy(table->productid, MPC_PRODUCT_ID, sizeof(MPC_PRODUCT_ID) - 1); | ||||
| 	table->lapic = APIC_DEFAULT_PHYS_BASE; | ||||
|  | ||||
| 	offset += ssize; | ||||
| 	ssize = sizeof(struct mpc_cpu); | ||||
|  | ||||
| 	fw_cfg_select(FW_CFG_NB_CPUS); | ||||
| 	num_cpus = fw_cfg_readl_le(); | ||||
| 	mptable_get_cpuid(&cpuid_stepping, &cpuid_features); | ||||
|  | ||||
| 	for (i = 0; i < num_cpus; i++) { | ||||
| 		cpu = (struct mpc_cpu *) (MPTABLE_START + offset); | ||||
| 		memset(cpu, 0, ssize); | ||||
| 		cpu->type = MP_PROCESSOR; | ||||
| 		cpu->apicid = i; | ||||
| 		cpu->apicver = APIC_VERSION; | ||||
| 		cpu->cpuflag = CPU_ENABLED; | ||||
| 		if (i == 0) { | ||||
| 			cpu->cpuflag |= CPU_BOOTPROCESSOR; | ||||
| 		} | ||||
| 		cpu->cpufeature = cpuid_stepping; | ||||
| 		cpu->featureflag = cpuid_features; | ||||
| 		checksum += mptable_checksum((char *) cpu, ssize); | ||||
| 		offset += ssize; | ||||
| 	} | ||||
|  | ||||
| 	ssize = sizeof(struct mpc_bus); | ||||
|  | ||||
| 	bus = (struct mpc_bus *) (MPTABLE_START + offset); | ||||
| 	memset(bus, 0, ssize); | ||||
| 	bus->type = MP_BUS; | ||||
| 	bus->busid = 0; | ||||
| 	memcpy(bus->bustype, BUS_TYPE_ISA, sizeof(BUS_TYPE_ISA) - 1); | ||||
| 	checksum += mptable_checksum((char *) bus, ssize); | ||||
|  | ||||
| 	offset += ssize; | ||||
| 	ssize = sizeof(struct mpc_ioapic); | ||||
|  | ||||
| 	ioapic = (struct mpc_ioapic *) (MPTABLE_START + offset); | ||||
| 	memset(ioapic, 0, ssize); | ||||
| 	ioapic->type = MP_IOAPIC; | ||||
| 	ioapic->apicid = num_cpus + 1; | ||||
| 	ioapic->apicver = APIC_VERSION; | ||||
| 	ioapic->flags = MPC_APIC_USABLE; | ||||
| 	ioapic->apicaddr = IO_APIC_DEFAULT_PHYS_BASE; | ||||
| 	checksum += mptable_checksum((char *) ioapic, ssize); | ||||
|  | ||||
| 	offset += ssize; | ||||
| 	ssize = sizeof(struct mpc_intsrc); | ||||
|  | ||||
| 	fw_cfg_select(FW_CFG_IRQ0_OVERRIDE); | ||||
| 	irq0_override = fw_cfg_readl_le(); | ||||
|  | ||||
| 	for (i = 0; i < 16; i++) { | ||||
| 		intsrc = (struct mpc_intsrc *) (MPTABLE_START + offset); | ||||
| 		memset(intsrc, 0, ssize); | ||||
| 		intsrc->type = MP_INTSRC; | ||||
| 		intsrc->irqtype = mp_INT; | ||||
| 		intsrc->irqflag = MP_IRQDIR_DEFAULT; | ||||
| 		intsrc->srcbus = 0; | ||||
| 		intsrc->srcbusirq = i; | ||||
| 		intsrc->dstapic = num_cpus + 1; | ||||
| 		intsrc->dstirq = i; | ||||
| 		if (irq0_override) { | ||||
| 			if (i == 0) { | ||||
| 				intsrc->dstirq = 2; | ||||
| 			} else if (i == 2) { | ||||
| 				// Don't update offset nor checksum | ||||
| 				continue; | ||||
| 			} | ||||
| 		} | ||||
| 		checksum += mptable_checksum((char *) intsrc, ssize); | ||||
| 		offset += ssize; | ||||
| 	} | ||||
|  | ||||
| 	ssize = sizeof(struct mpc_lintsrc); | ||||
|  | ||||
| 	lintsrc = (struct mpc_lintsrc *) (MPTABLE_START + offset); | ||||
| 	memset(lintsrc, 0, ssize); | ||||
| 	lintsrc->type = MP_LINTSRC; | ||||
| 	lintsrc->irqtype = mp_ExtINT; | ||||
| 	lintsrc->irqflag = MP_IRQDIR_DEFAULT; | ||||
| 	lintsrc->srcbusid = 0; | ||||
| 	lintsrc->srcbusirq = 0; | ||||
| 	lintsrc->destapic = 0; | ||||
| 	lintsrc->destapiclint = 0; | ||||
| 	checksum += mptable_checksum((char *) lintsrc, ssize); | ||||
|  | ||||
| 	offset += ssize; | ||||
|  | ||||
| 	lintsrc = (struct mpc_lintsrc *) (MPTABLE_START + offset); | ||||
| 	lintsrc->type = MP_LINTSRC; | ||||
| 	lintsrc->irqtype = mp_NMI; | ||||
| 	lintsrc->irqflag = MP_IRQDIR_DEFAULT; | ||||
| 	lintsrc->srcbusid = 0; | ||||
| 	lintsrc->srcbusirq = 0; | ||||
| 	lintsrc->destapic = 0xFF; | ||||
| 	lintsrc->destapiclint = 1; | ||||
| 	checksum += mptable_checksum((char *) lintsrc, ssize); | ||||
|  | ||||
| 	offset += ssize; | ||||
| 	ssize = sizeof(struct mpc_table); | ||||
|  | ||||
| 	table->length = offset - sizeof(struct mpf_intel); | ||||
| 	checksum += mptable_checksum((char *) table, ssize); | ||||
| 	table->checksum -= checksum; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user