[Soekris] linux on the net4501

skmail@mcewen.wcnet.org skmail at mcewen.wcnet.org
Tue Apr 9 03:49:08 UTC 2002


With this being so long ago surely it's fixed by now?


On Mon, 8 Apr 2002, David LeBlanc wrote:

> I also found this mail message on the Yahoo linux-kernel forum. It probably
> depends on the bios being used, so may not apply to the net4501 at all.
> 
> From: Brian Moyle  <bmoyle at m...>
> Date: Thu Mar 1, 2001 8:56am
> Subject: Re: 2.4.2-ac6 hangs on boot w/AMD Elan SC520 dev board
> 
> 
>   I believe the following patch fixes the problem (it worked on the few
> machines I tested).
> 
> Is this along the lines of what you were thinking?
> 
> Brian
> bmoyle at m...
> 
> Alan Cox wrote:
> > Having been over the code the problem is indeed the bios reporting
> overlapping
> > /duplicated ranges. That will cause a crash in mm/bootmem when we try and
> free
> > the range twice.
> >
> > I suspect you need to add some code to take the E820 map and remove any
> > overlaps from it, favouring ROM over RAM if the types disagree (for
> safety),
> > and filter them before you register them with the bootmem in
> > arch/i386/kernel/setup.c
> 
> --- linux-2.4.2-ac6/arch/i386/kernel/setup.c	Thu Mar  1 00:24:26 2001
> +++ linux/arch/i386/kernel/setup.c	Thu Mar  1 00:29:34 2001
> @@ -58,6 +58,9 @@
>   *  Massive cleanup of CPU detection and bug handling;
>   *  Transmeta CPU detection,
>   *  H. Peter Anvin <hpa at z...>, November 2000
> + *
> + *  Added E820 sanitization routine (removes overlapping memory regions);
> + *  Brian Moyle <bmoyle at m...>, February 2001
>   */
> 
>  /*
> @@ -438,6 +441,126 @@
>  }
> 
>  /*
> + * 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;
> +	int i;
> +
> +	/* 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) */
> +	chgidx = 0;
> +	for (i=0; i < old_nr; i++)	{
> +		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];
> +	}
> +
> +	/* sort change-point list by memory addresses (low -> high) */
> +	still_changing = 1;
> +	while (still_changing)	{
> +		still_changing = 0;
> +		for (i=1; i < 2*old_nr; i++)
> +		{
> +			if (change_point[i]->addr < change_point[i-1]->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 < 2*old_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,+=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;
> +				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..
> @@ -504,6 +627,7 @@
>  	 * 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;
> 
> @@ -2267,7 +2391,7 @@
>  			p+=sprintf(p, " (%dMhz/%dMhz FSB)\n", c->cpuclock,
>  						c->busclock);
>  		else if(c->busclock)
> -			p+sprintf(p, " (%dMhz FSB)\n", c->busclock);
> +			p+=sprintf(p, " (%dMhz FSB)\n", c->busclock);
>  		else
>  			p+=sprintf(p, "\n");
> 
> 
> 
> 
> 
> David LeBlanc
> Seattle, WA USA
> 
> _____________________________________________________________________
> Soekris Engineering, technical discussion mailing list
> [un]subscribe: http://lists.soekris.com/mailman/listinfo/soekris-tech
> 




More information about the Soekris-tech mailing list