setup.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,468 行 · 第 1/5 页

C
2,468
字号
				printk("(ACPI NVS)\n");				break;		default:	printk("type %lu\n", e820.map[i].type);				break;		}	}}/* * Sanitize the BIOS e820 map. * * Some e820 responses include overlapping entries.  The following  * replaces the original e820 map with a new one, removing overlaps. * */static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map){	struct change_member {		struct e820entry *pbios; /* pointer to original bios entry */		unsigned long long addr; /* address for this change point */	};	struct change_member change_point_list[2*E820MAX];	struct change_member *change_point[2*E820MAX];	struct e820entry *overlap_list[E820MAX];	struct e820entry new_bios[E820MAX];	struct change_member *change_tmp;	unsigned long current_type, last_type;	unsigned long long last_addr;	int chgidx, still_changing;	int overlap_entries;	int new_bios_entry;	int old_nr, new_nr, chg_nr;	int i;	/*		Visually we're performing the following (1,2,3,4 = memory types)...		Sample memory map (w/overlaps):		   ____22__________________		   ______________________4_		   ____1111________________		   _44_____________________		   11111111________________		   ____________________33__		   ___________44___________		   __________33333_________		   ______________22________		   ___________________2222_		   _________111111111______		   _____________________11_		   _________________4______		Sanitized equivalent (no overlap):		   1_______________________		   _44_____________________		   ___1____________________		   ____22__________________		   ______11________________		   _________1______________		   __________3_____________		   ___________44___________		   _____________33_________		   _______________2________		   ________________1_______		   _________________4______		   ___________________2____		   ____________________33__		   ______________________4_	*/	/* if there's only one memory region, don't bother */	if (*pnr_map < 2)		return -1;	old_nr = *pnr_map;	/* bail out if we find any unreasonable addresses in bios map */	for (i=0; i<old_nr; i++)		if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)			return -1;	/* create pointers for initial change-point information (for sorting) */	for (i=0; i < 2*old_nr; i++)		change_point[i] = &change_point_list[i];	/* record all known change-points (starting and ending addresses),	   omitting those that are for empty memory regions */	chgidx = 0;	for (i=0; i < old_nr; i++)	{		if (biosmap[i].size != 0) {			change_point[chgidx]->addr = biosmap[i].addr;			change_point[chgidx++]->pbios = &biosmap[i];			change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;			change_point[chgidx++]->pbios = &biosmap[i];		}	}	chg_nr = chgidx;    	/* true number of change-points */	/* sort change-point list by memory addresses (low -> high) */	still_changing = 1;	while (still_changing)	{		still_changing = 0;		for (i=1; i < chg_nr; i++)  {			/* if <current_addr> > <last_addr>, swap */			/* or, if current=<start_addr> & last=<end_addr>, swap */			if ((change_point[i]->addr < change_point[i-1]->addr) ||				((change_point[i]->addr == change_point[i-1]->addr) &&				 (change_point[i]->addr == change_point[i]->pbios->addr) &&				 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))			   )			{				change_tmp = change_point[i];				change_point[i] = change_point[i-1];				change_point[i-1] = change_tmp;				still_changing=1;			}		}	}	/* create a new bios memory map, removing overlaps */	overlap_entries=0;	 /* number of entries in the overlap table */	new_bios_entry=0;	 /* index for creating new bios map entries */	last_type = 0;		 /* start with undefined memory type */	last_addr = 0;		 /* start with 0 as last starting address */	/* loop through change-points, determining affect on the new bios map */	for (chgidx=0; chgidx < chg_nr; chgidx++)	{		/* keep track of all overlapping bios entries */		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)		{			/* add map entry to overlap list (> 1 entry implies an overlap) */			overlap_list[overlap_entries++]=change_point[chgidx]->pbios;		}		else		{			/* remove entry from list (order independent, so swap with last) */			for (i=0; i<overlap_entries; i++)			{				if (overlap_list[i] == change_point[chgidx]->pbios)					overlap_list[i] = overlap_list[overlap_entries-1];			}			overlap_entries--;		}		/* if there are overlapping entries, decide which "type" to use */		/* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */		current_type = 0;		for (i=0; i<overlap_entries; i++)			if (overlap_list[i]->type > current_type)				current_type = overlap_list[i]->type;		/* continue building up new bios map based on this information */		if (current_type != last_type)	{			if (last_type != 0)	 {				new_bios[new_bios_entry].size =					change_point[chgidx]->addr - last_addr;				/* move forward only if the new size was non-zero */				if (new_bios[new_bios_entry].size != 0)					if (++new_bios_entry >= E820MAX)						break; 	/* no more space left for new bios entries */			}			if (current_type != 0)	{				new_bios[new_bios_entry].addr = change_point[chgidx]->addr;				new_bios[new_bios_entry].type = current_type;				last_addr=change_point[chgidx]->addr;			}			last_type = current_type;		}	}	new_nr = new_bios_entry;   /* retain count for new bios entries */	/* copy new bios mapping into original location */	memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));	*pnr_map = new_nr;	return 0;}/* * Copy the BIOS e820 map into a safe place. * * Sanity-check it while we're at it.. * * If we're lucky and live on a modern system, the setup code * will have given us a memory map that we can use to properly * set up memory.  If we aren't, we'll fake a memory map. * * We check to see that the memory map contains at least 2 elements * before we'll use it, because the detection code in setup.S may * not be perfect and most every PC known to man has two memory * regions: one from 0 to 640k, and one from 1mb up.  (The IBM * thinkpad 560x, for example, does not cooperate with the memory * detection code.) */static int __init copy_e820_map(struct e820entry * biosmap, int nr_map){	/* Only one memory region (or negative)? Ignore it */	if (nr_map < 2)		return -1;	do {		unsigned long long start = biosmap->addr;		unsigned long long size = biosmap->size;		unsigned long long end = start + size;		unsigned long type = biosmap->type;		/* Overflow in 64 bits? Ignore the memory map. */		if (start > end)			return -1;		/*		 * Some BIOSes claim RAM in the 640k - 1M region.		 * Not right. Fix it up.		 */		if (type == E820_RAM) {			if (start < 0x100000ULL && end > 0xA0000ULL) {				if (start < 0xA0000ULL)					add_memory_region(start, 0xA0000ULL-start, type);				if (end <= 0x100000ULL)					continue;				start = 0x100000ULL;				size = end - start;			}		}		add_memory_region(start, size, type);	} while (biosmap++,--nr_map);	return 0;}#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)unsigned char eddnr;struct edd_info edd[EDDMAXNR];unsigned int edd_disk80_sig;/** * copy_edd() - Copy the BIOS EDD information *              from empty_zero_page into a safe place. * */static inline void copy_edd(void){     eddnr = EDD_NR;     memcpy(edd, EDD_BUF, sizeof(edd));     edd_disk80_sig = DISK80_SIGNATURE_BUFFER;}#elsestatic inline void copy_edd(void) {}#endif/* * Do NOT EVER look at the BIOS memory size location. * It does not work on many machines. */#define LOWMEMSIZE()	(0x9f000)static void __init setup_memory_region(void){	char *who = "BIOS-e820";	/*	 * Try to copy the BIOS-supplied E820-map.	 *	 * Otherwise fake a memory map; one section from 0k->640k,	 * the next section from 1mb->appropriate_mem_k	 */	sanitize_e820_map(E820_MAP, &E820_MAP_NR);	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {		unsigned long mem_size;		/* compare results from other methods and take the greater */		if (ALT_MEM_K < EXT_MEM_K) {			mem_size = EXT_MEM_K;			who = "BIOS-88";		} else {			mem_size = ALT_MEM_K;			who = "BIOS-e801";		}		e820.nr_map = 0;		add_memory_region(0, LOWMEMSIZE(), E820_RAM);		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);  	}	printk(KERN_INFO "BIOS-provided physical RAM map:\n");	print_memory_map(who);} /* setup_memory_region */static void __init parse_cmdline_early (char ** cmdline_p){	char c = ' ', *to = command_line, *from = COMMAND_LINE;	int len = 0;	int userdef = 0;	/* Save unparsed command line copy for /proc/cmdline */	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';	for (;;) {		if (c != ' ')			goto nextchar;		/*		 * "mem=nopentium" disables the 4MB page tables.		 * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM		 * to <mem>, overriding the bios size.		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from		 * <start> to <start>+<mem>, overriding the bios size.		 */		if (!memcmp(from, "mem=", 4)) {			if (to != command_line)				to--;			if (!memcmp(from+4, "nopentium", 9)) {				from += 9+4;				clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);				set_bit(X86_FEATURE_PSE, &disabled_x86_caps);			} else if (!memcmp(from+4, "exactmap", 8)) {				from += 8+4;				e820.nr_map = 0;				userdef = 1;			} else {				/* If the user specifies memory size, we				 * limit the BIOS-provided memory map to				 * that size. exactmap can be used to specify				 * the exact map. mem=number can be used to				 * trim the existing memory map.				 */				unsigned long long start_at, mem_size; 				mem_size = memparse(from+4, &from);				if (*from == '@') {					start_at = memparse(from+1, &from);					add_memory_region(start_at, mem_size, E820_RAM);				} else if (*from == '#') {					start_at = memparse(from+1, &from);					add_memory_region(start_at, mem_size, E820_ACPI);				} else if (*from == '$') {					start_at = memparse(from+1, &from);					add_memory_region(start_at, mem_size, E820_RESERVED);				} else {					limit_regions(mem_size);					userdef=1;				}			}		}#ifdef	CONFIG_SMP		/*		 * If the BIOS enumerates physical processors before logical,		 * maxcpus=N at enumeration-time can be used to disable HT.		 */		else if (!memcmp(from, "maxcpus=", 8)) {			extern unsigned int max_cpus;			max_cpus = simple_strtoul(from + 8, NULL, 0);		}#endif#ifdef CONFIG_ACPI_BOOT		/* "acpi=off" disables both ACPI table parsing and interpreter */		else if (!memcmp(from, "acpi=off", 8)) {			disable_acpi();		}		/* acpi=force to over-ride black-list */		else if (!memcmp(from, "acpi=force", 10)) { 			acpi_force = 1;			acpi_ht = 1;			acpi_disabled = 0;		} 		/* Limit ACPI to boot-time only, still enabled HT */		else if (!memcmp(from, "acpi=ht", 7)) { 			if (!acpi_force)				disable_acpi();			acpi_ht = 1; 		} 		/* acpi=strict disables out-of-spec workarounds */		else if (!memcmp(from, "acpi=strict", 11)) {			acpi_strict = 1;		}		else if (!memcmp(from, "pci=noacpi", 10)) { 			acpi_noirq_set();		}                /* disable IO-APIC */                else if (!memcmp(from, "noapic", 6))                        disable_ioapic_setup();		else if (!memcmp(from, "acpi_sci=edge", 13))			acpi_sci_flags.trigger =  1;		else if (!memcmp(from, "acpi_sci=level", 14))			acpi_sci_flags.trigger = 3;		else if (!memcmp(from, "acpi_sci=high", 13))			acpi_sci_flags.polarity = 1;		else if (!memcmp(from, "acpi_sci=low", 12))			acpi_sci_flags.polarity = 3;#endif		/*		 * highmem=size forces highmem to be exactly 'size' bytes.		 * This works even on boxes that have no highmem otherwise.		 * This also works to reduce highmem size on bigger boxes.		 */		else if (!memcmp(from, "highmem=", 8))			highmem_pages = memparse(from+8, &from) >> PAGE_SHIFT;nextchar:		c = *(from++);		if (!c)			break;		if (COMMAND_LINE_SIZE <= ++len)			break;		*(to++) = c;	}	*to = '\0';	*cmdline_p = command_line;	if (userdef) {		printk(KERN_INFO "user-defined physical RAM map:\n");		print_memory_map("user");	}}#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)#define PFN_PHYS(x)	((x) << PAGE_SHIFT)/* * Reserved space for vmalloc and iomap - defined in asm/page.h */#define MAXMEM_PFN	PFN_DOWN(MAXMEM)#define MAX_NONPAE_PFN	(1 << 20)/* * Find the highest page frame number we have available */static void __init find_max_pfn(void){	int i;	max_pfn = 0;	for (i = 0; i < e820.nr_map; i++) {		unsigned long start, end;		/* RAM? */		if (e820.map[i].type != E820_RAM)			continue;		start = PFN_UP(e820.map[i].addr);		end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);		if (start >= end)			continue;		if (end > max_pfn)			max_pfn = end;	}}/* * Determine low and high memory ranges: */static unsigned long __init find_max_low_pfn(void){	unsigned long max_low_pfn;	max_low_pfn = max_pfn;	if (max_low_pfn > MAXMEM_PFN) {		if (highmem_pages == -1)			highmem_pages = max_pfn - MAXMEM_PFN;		if (highmem_pages + MAXMEM_PFN < max_pfn)			max_pfn = MAXMEM_PFN + highmem_pages;		if (highmem_pages + MAXMEM_PFN > max_pfn) {			printk("only %luMB highmem pages available, ignoring highmem size of %uMB.\n", pages_to_mb(max_pfn - MAXMEM_PFN), pages_to_mb(highmem_pages));			highmem_pages = 0;		}		max_low_pfn = MAXMEM_PFN;#ifndef CONFIG_HIGHMEM		/* Maximum memory usable is what is directly addressable */		printk(KERN_WARNING "Warning only %ldMB will be used.\n",					MAXMEM>>20);		if (max_pfn > MAX_NONPAE_PFN)			printk(KERN_WARNING "Use a PAE enabled kernel.\n");		else			printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");#else /* !CONFIG_HIGHMEM */#ifndef CONFIG_X86_PAE		if (max_pfn > MAX_NONPAE_PFN) {			max_pfn = MAX_NONPAE_PFN;			printk(KERN_WARNING "Warning only 4GB will be used.\n");			printk(KERN_WARNING "Use a PAE enabled kernel.\n");		}#endif /* !CONFIG_X86_PAE */#endif /* !CONFIG_HIGHMEM */	} else {		if (highmem_pages == -1)			highmem_pages = 0;#if CONFIG_HIGHMEM		if (highmem_pages >= max_pfn) {			printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn));			highmem_pages = 0;		}		if (highmem_pages) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?