- Support for a LinuxBIOS version number (start at 1.0.0)

- Support for remember our compile time environment
- Simple and always correct version of compute_ip_checksum
- Improve message strings in crt0.base
- Initial support for > 2G ram.
  - Sizeram now returns a list of valid ranges of ram
  - pci resource allocation now starts at 0xC0000000
- Update sizeram for every northbridge
- Misc cleanups.
This commit is contained in:
Eric W. Biederman 2002-07-02 07:13:12 +00:00
commit e803bc7bd4
63 changed files with 1370 additions and 912 deletions

340
COPYING Normal file
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View file

@ -1,8 +1,11 @@
#include <mem.h>
#include <ip_checksum.h>
#include <boot/linuxbios_tables.h>
#include <boot/linuxbios_table.h>
#include <printk.h>
#include <string.h>
#include <version.h>
struct lb_header *lb_table_init(unsigned long addr)
{
@ -73,28 +76,58 @@ struct lb_memory *lb_memory(struct lb_header *header)
struct lb_mainboard *lb_mainboard(struct lb_header *header)
{
#define __STR(X) #X
#define STR(X) __STR(X)
static const char vendor[] = STR(MAINBOARD_VENDOR);
static const char part_number[] = STR(MAINBOARD_PART_NUMBER);
struct lb_record *rec;
struct lb_mainboard *mainboard;
rec = lb_new_record(header);
mainboard = (struct lb_mainboard *)rec;
mainboard->tag = LB_TAG_MAINBOARD;
mainboard->size = sizeof(*mainboard) +
sizeof(vendor) + sizeof(part_number);
mainboard->size = (sizeof(*mainboard) +
strlen(mainboard_vendor) + 1 +
strlen(mainboard_part_number) + 1 +
3) & ~3;
mainboard->vendor_idx = 0;
mainboard->part_number_idx = sizeof(vendor);
mainboard->part_number_idx = strlen(mainboard_vendor) + 1;
memcpy(mainboard->strings + mainboard->vendor_idx,
vendor, sizeof(vendor));
mainboard_vendor, strlen(mainboard_vendor) + 1);
memcpy(mainboard->strings + mainboard->part_number_idx,
part_number, sizeof(part_number));
#undef STR
#undef __STR
mainboard_part_number, strlen(mainboard_part_number) + 1);
return mainboard;
}
void lb_strings(struct lb_header *header)
{
static const struct {
uint32_t tag;
const uint8_t *string;
} strings[] = {
{ LB_TAG_VERSION, linuxbios_version, },
{ LB_TAG_EXTRA_VERSION, linuxbios_extra_version, },
{ LB_TAG_BUILD, linuxbios_build, },
{ LB_TAG_COMPILE_TIME, linuxbios_compile_time, },
{ LB_TAG_COMPILE_BY, linuxbios_compile_by, },
{ LB_TAG_COMPILE_HOST, linuxbios_compile_host, },
{ LB_TAG_COMPILE_DOMAIN, linuxbios_compile_domain, },
{ LB_TAG_COMPILER, linuxbios_compiler, },
{ LB_TAG_LINKER, linuxbios_linker, },
{ LB_TAG_ASSEMBLER, linuxbios_assembler, },
};
int i;
for(i = 0; i < sizeof(strings)/sizeof(strings[0]); i++) {
struct lb_string *rec;
size_t len;
rec = lb_new_record(header);
len = strlen(strings[i].string);
rec->tag = strings[i].tag;
rec->size = (sizeof(*rec) + len + 1 + 3) & ~3;
memcpy(rec->string, strings[i].string, len+1);
}
}
/* Some version of gcc have problems with 64 bit types so
* take an unsigned long instead of a uint64_t for now.
*/
@ -109,6 +142,19 @@ void lb_memory_range(struct lb_memory *mem,
mem->size += sizeof(mem->map[0]);
}
static void lb_memory_rangek(struct lb_memory *mem,
uint32_t type, unsigned long startk, unsigned long endk)
{
int entries;
entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]);
mem->map[entries].start = startk;
mem->map[entries].start <<= 10;
mem->map[entries].size = endk - startk;
mem->map[entries].size <<= 10;
mem->map[entries].type = type;
mem->size += sizeof(mem->map[0]);
}
static void lb_reserve_table_memory(struct lb_header *head)
{
struct lb_record *last_rec;
@ -173,14 +219,16 @@ struct lb_memory *get_lb_mem(void)
unsigned long write_linuxbios_table(
unsigned long *processor_map,
unsigned long totalram,
struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_start, unsigned long rom_table_end)
unsigned long rom_table_startk, unsigned long rom_table_endk)
{
unsigned long table_size;
struct mem_range *ramp;
struct lb_header *head;
struct lb_memory *mem;
struct lb_record *rec_dest, *rec_src;
head = lb_table_init(low_table_end);
low_table_end = (unsigned long)head;
#if HAVE_OPTION_TABLE == 1
@ -191,18 +239,40 @@ unsigned long write_linuxbios_table(
#endif
mem = lb_memory(head);
mem_ranges = mem;
/* I assume there is always ram at address 0 */
/* Reserve our tables in low memory */
lb_memory_range(mem, LB_MEM_RESERVED, low_table_start, low_table_end - low_table_start);
lb_memory_range(mem, LB_MEM_RAM, low_table_end, 640*1024 - low_table_end);
/* Reserve the whole dos BIOS reserved area, we can probably do
* better but it isn't too important right now
table_size = (low_table_end - low_table_start);
lb_memory_range(mem, LB_MEM_TABLE, 0, table_size);
lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size);
/* Reserving pci memory mapped space will keep the kernel from booting seeing
* any pci resources.
*/
lb_memory_range(mem, LB_MEM_RESERVED, 0x000a0000, 0x00060000);
/* Now show all of memory */
lb_memory_range(mem, LB_MEM_RAM, 0x00100000, (totalram - 1024) << 10);
for(ramp = &ram[1]; ramp->sizek; ramp++) {
unsigned long startk, endk;
startk = ramp->basek;
endk = startk + ramp->sizek;
if ((startk < rom_table_startk) && (endk > rom_table_startk)) {
lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk);
startk = rom_table_startk;
}
if ((startk == rom_table_startk) && (endk > startk)) {
unsigned long tend;
tend = rom_table_endk;
if (tend > endk) {
tend = endk;
}
lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend);
startk = tend;
}
if (endk > startk) {
lb_memory_rangek(mem, LB_MEM_RAM, startk, endk);
}
}
/* Record our motheboard */
lb_mainboard(head);
/* Record our various random string information */
lb_strings(head);
low_table_end = lb_table_fini(head);

View file

@ -124,6 +124,6 @@ __main:
jmp .Lhlt
.section ".rom.data"
str_after_ram: .string "Ram Initialize?\r\n"
str_pre_main: .string "before main\r\n"
str_after_ram: .string "Copying LinuxBIOS to ram.\r\n"
str_pre_main: .string "Jumping to LinuxBIOS.\r\n"
.previous

View file

@ -1,7 +1,6 @@
#ifndef ASM_I386_BOOT_H
#define ASM_I386_BOOT_H
#define UBE32
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_386

View file

@ -1,7 +1,8 @@
#ifndef I386_SUBR_H
#define I386_SUBR_H
void cache_on(unsigned long totalram);
struct mem_range;
void cache_on(struct mem_range *mem);
void interrupts_on(void);
#endif /* I386_SUBR_H */

View file

@ -2,8 +2,22 @@
jmp console0
console_test: .string "\r\n\r\nLinuxBIOS starting...\r\n"
#define __STR(X) #X
#define STR(X) __STR(X)
#ifndef LINUXBIOS_EXTRA_VERSION
#define LINUXBIOS_EXTRA_VERSION
#endif
console_test:
.ascii "\r\n\r\nLinuxBIOS-"
.ascii STR(LINUXBIOS_VERSION)
.ascii STR(LINUXBIOS_EXTRA_VERSION)
.ascii " "
.ascii STR(LINUXBIOS_BUILD)
.asciz " starting...\r\n"
#undef STR
/* uses: ax, dx */
#if defined(SERIAL_CONSOLE)
#define __CONSOLE_INLINE_TX_AL TTYS0_TX_AL
@ -229,7 +243,7 @@ console_test: .string "\r\n\r\nLinuxBIOS starting...\r\n"
#define CONSOLE_SPEW_TX_STRING(string) __CONSOLE_TX_STRING(string)
#define CONSOLE_SPEW_INLINE_TX_STRING(string) __CONSOLE_INLINE_TX_STRING(string)
#if ASM_CONSOLE_LOGLEVEL <= BIOS_SPEW
#if ASM_CONSOLE_LOGLEVEL <= BIOS_EMERG
#undef CONSOLE_EMERG_TX_CHAR
#undef CONSOLE_EMERG_INLINE_TX_CHAR
#undef CONSOLE_EMERG_TX_HEX8

View file

@ -42,6 +42,8 @@ static char rcsid[] = "$Id$";
#include <pci.h>
#include <subr.h>
#include <printk.h>
#include <mem.h>
#include <version.h>
#include <smp/start_stop.h>
#include <cpu/l2_cache.h>
#include <cpu/cpufixup.h>
@ -76,7 +78,7 @@ static char rcsid[] = "$Id$";
*/
static unsigned long processor_map[MAX_CPUS];
static unsigned long cpu_initialize(unsigned long totalram)
static unsigned long cpu_initialize(struct mem_range *mem)
{
/* Because we busy wait at the printk spinlock.
* It is important to keep the number of printed messages
@ -87,10 +89,10 @@ static unsigned long cpu_initialize(unsigned long totalram)
printk_notice("Initializing CPU #%d\n", processor_id);
/* some cpus need a fixup done. This is the hook for doing that. */
cpufixup(totalram);
cpufixup(mem);
/* Turn on caching if we haven't already */
cache_on(totalram);
cache_on(mem);
display_cpuid();
mtrr_check();
@ -105,16 +107,18 @@ static unsigned long cpu_initialize(unsigned long totalram)
return processor_id;
}
static unsigned long get_ramsize(void)
static struct mem_range *get_ramsize(void)
{
unsigned long totalram;
totalram = sizeram();
// can't size just yet ...
// mainboard totalram sizing may not be up yet. If it is not ready,
// take a default of 64M
if (!totalram)
totalram = 64 * 1024;
return totalram;
static struct mem_range *mem = 0;
if (!mem) {
mem = sizeram();
}
if (!mem) {
printk_err("No memory size information!\n");
for(;;);
}
return mem;
}
#ifdef SMP
@ -123,14 +127,14 @@ static atomic_t active_cpus = ATOMIC_INIT(1);
void secondary_cpu_init(void)
{
unsigned long totalram;
struct mem_range *mem;
unsigned long id;
int index;
atomic_inc(&active_cpus);
printk_debug(__FUNCTION__ "\n");
totalram = get_ramsize();
id = cpu_initialize(totalram);
mem = get_ramsize();
id = cpu_initialize(mem);
index = processor_index(id);
printk_debug(__FUNCTION__ " %d/%u\n", index, id);
processor_map[index] = CPU_ENABLED;
@ -153,7 +157,7 @@ static void wait_for_other_cpus(void)
}
active_count = atomic_read(&active_cpus);
}
for (i = 0; i < MAX_CPUS; i++) {
for(i = 0; i < MAX_CPUS; i++) {
if (!(processor_map[i] & CPU_ENABLED)) {
printk_err("CPU %d/%u did not initialize!\n",
i, initial_apicid[i]);
@ -185,7 +189,7 @@ static void remove_logical_cpus(void)
#endif /* SMP */
void write_tables(unsigned long totalram)
void write_tables(struct mem_range *mem)
{
unsigned long low_table_start, low_table_end;
unsigned long rom_table_start, rom_table_end;
@ -193,7 +197,7 @@ void write_tables(unsigned long totalram)
rom_table_start = 0xf0000;
rom_table_end = 0xf0000;
/* Start low addr at 16 bytes instead of 0 because of a buglet
* in the generic linux bunzip code, as it tests for the a20 line.
* in the generic linux unzip code, as it tests for the a20 line.
*/
low_table_start = 0;
low_table_end = 16;
@ -202,6 +206,7 @@ void write_tables(unsigned long totalram)
check_pirq_routing_table();
/* This table must be betweeen 0xf0000 & 0x100000 */
rom_table_end = copy_pirq_routing_table(rom_table_end);
rom_table_end = (rom_table_end + 1023) & ~1023;
/* copy the smp block to address 0 */
post_code(0x96);
@ -214,9 +219,9 @@ void write_tables(unsigned long totalram)
low_table_end = 0x500;
}
/* The linuxbios table must be in 0-4K or 960K-1M */
write_linuxbios_table(processor_map, totalram,
write_linuxbios_table(processor_map, mem,
low_table_start, low_table_end,
rom_table_start, rom_table_end);
rom_table_start >> 10, rom_table_end >> 10);
}
void hardwaremain(int boot_complete)
@ -244,8 +249,9 @@ void hardwaremain(int boot_complete)
* things, so that the other work can use the PciRead* and PciWrite*
* functions.
*/
unsigned long totalram = 0;
extern void linuxbiosmain(unsigned long membase, unsigned long totalram);
struct mem_range *mem, *tmem;
unsigned long totalmem;
extern void linuxbiosmain(struct mem_range *mem);
// we don't call post code for this one -- since serial post could cause real
// trouble.
@ -254,8 +260,9 @@ void hardwaremain(int boot_complete)
displayinit();
post_code(0x39);
printk_notice("LinuxBIOS %s...\n", (boot_complete) ? "rebooting" : "booting");
printk_notice("LinuxBIOS-%s%s %s %s...\n",
linuxbios_version, linuxbios_extra_version, linuxbios_build,
(boot_complete)?"rebooting":"booting");
post_code(0x40);
@ -278,12 +285,17 @@ void hardwaremain(int boot_complete)
// So you really need to run this before you size ram.
framebuffer_on();
totalram = get_ramsize();
mem = get_ramsize();
post_code(0x70);
printk_info("totalram: %ldM\n", totalram/1024);
totalmem = 0;
for(tmem = mem; tmem->sizek; tmem++) {
totalmem += tmem->sizek;
}
printk_info("totalram: %ldM\n",
(totalmem + 512) >> 10); /* Round to the nearest meg */
/* Fully initialize the cpu before configuring the bus */
boot_cpu = cpu_initialize(totalram);
boot_cpu = cpu_initialize(mem);
boot_index = processor_index(boot_cpu);
printk_spew("BOOT CPU is %d\n", boot_cpu);
processor_map[boot_index] = CPU_BOOTPROCESSOR|CPU_ENABLED;
@ -378,14 +390,14 @@ void hardwaremain(int boot_complete)
/* Now that we have collected all of our information
* write our configuration tables.
*/
write_tables(totalram);
write_tables(mem);
#ifdef LINUXBIOS
printk_info("Jumping to linuxbiosmain()...\n");
// we could go to argc, argv, for main but it seems like overkill.
post_code(0xed);
linuxbiosmain(0, totalram);
linuxbiosmain(mem);
#endif /* LINUXBIOS */
}
@ -393,6 +405,3 @@ void hardwaremain(int boot_complete)

View file

@ -1,3 +1,4 @@
#include <mem.h>
#include <cpu/p5/io.h>
#include <cpu/p5/macros.h>
#include <cpu/p6/msr.h>
@ -13,7 +14,7 @@
#define APIC 1
#endif
void cache_on(unsigned long totalram)
void cache_on(struct mem_range *mem)
{
post_code(0x60);
printk_info("Enabling cache...");
@ -32,7 +33,7 @@ void cache_on(unsigned long totalram)
#if defined(i686)
// totalram here is in linux sizing, i.e. units of KB.
// set_mtrr is responsible for getting it into the right units!
setup_mtrrs(totalram);
setup_mtrrs(mem);
#endif
post_code(0x6A);

View file

@ -1,5 +1,7 @@
## This is Architecture independant part of the makefile
option LINUXBIOS_VERSION=1.0.0
option CROSS_COMPILE=
makedefine CC:=$(CROSS_COMPILE)gcc
@ -14,6 +16,15 @@ makedefine CFLAGS := $(CPU_OPT) $(CPPFLAGS) -Os -nostdinc -nostdlib -fno-builtin
makedefine HOSTCC:=gcc
makedefine HOSTCFLAGS:= -Os -Wall
option LINUXBIOS_BUILD = $(shell date)
option LINUXBIOS_COMPILE_TIME = $(shell date +%T)
option LINUXBIOS_COMPILE_BY = $(shell whoami)
option LINUXBIOS_COMPILE_HOST = $(shell hostname)
option LINUXBIOS_COMPILE_DOMAIN = $(shell dnsdomainname)
option LINUXBIOS_COMPILER = $(shell $(CC) $(CFLAGS) -v 2>&1 | tail -1)
option LINUXBIOS_LINKER = $(shell $(CC) -Wl,-v 2>&1 | grep version | tail -1)
option LINUXBIOS_ASSEMBLER = $(shell touch dummy.s ; $(CC) -c -Wa,-v dummy.s 2>&1; rm -f dummy.s dummy.o )
makerule ldscript.ld : ldoptions $(LDSUBSCRIPTS-1) ; echo "INCLUDE ldoptions" > $@ ; for file in $(LDSUBSCRIPTS-1) ; do echo "INCLUDE $$file" >> $@ ; done
makerule cpuflags : Makefile.settings ; perl -e 'print "CPUFLAGS :=\n"; foreach $$var (split(" ", $$ENV{VARIABLES})) { if (exists($$ENV{$$var})) { print "CPUFLAGS += -D$$var" . (length($$ENV{$$var})?"=\x27$$ENV{$$var}\x27":"") ."\n"} else { print "CPUFLAGS += -U$$var\n"} }' > $@
@ -34,6 +45,8 @@ addaction linuxbios.a ar cr linuxbios.a $(OBJECTS-1)
option CRT0=$(TOP)/src/arch/$(ARCH)/config/crt0.base
makerule crt0.S: $(CRT0) ; cp $< $@
# Force crt0.s (which has build time version code in it to rebuild every time)
makedefine .PHONY : crt0.s
makerule crt0.s: crt0.S crt0_includes.h $(CRT0_INCLUDES); @echo "$(CPP) ... $< > $@ "
addaction crt0.s @$(CPP) $(CPPFLAGS) -I$(TOP)/src $< > $@.new && mv $@.new $@

View file

@ -0,0 +1,23 @@
/*
* Put the processor back into a reset state
* with respect to the xmm registers.
*/
pxor %xmm0, %xmm0
pxor %xmm1, %xmm1
pxor %xmm2, %xmm2
pxor %xmm3, %xmm3
pxor %xmm4, %xmm4
pxor %xmm5, %xmm5
pxor %xmm6, %xmm6
pxor %xmm7, %xmm7
/* Disable floating point emulation */
movl %cr0, %eax
andl $~(1<<2), %eax
movl %eax, %cr0
/* Disable sse instructions */
movl %cr4, %eax
andl $~(3<<9), %eax
movl %eax, %cr4

View file

@ -0,0 +1,13 @@
/*
* Enable the use of the xmm registers
*/
/* Disable floating point emulation */
movl %cr0, %eax
andl $~(1<<2), %eax
movl %eax, %cr0
/* Enable sse instructions */
movl %cr4, %eax
orl $(1<<9), %eax
movl %eax, %cr4

View file

@ -1,3 +1,4 @@
option i586=1
object cpuid.o
object delay_tsc.o
#object tsc.o

View file

@ -334,7 +334,7 @@ static void display_cpuid_update_microcode(void)
}
}
void p6_cpufixup(unsigned long totalram)
void p6_cpufixup(struct mem_range *mem)
{
printk_info("Updating microcode\n");
display_cpuid_update_microcode();

View file

@ -29,6 +29,7 @@
static char rcsid[] = "$Id$";
#endif
#include <mem.h>
#include <cpu/p6/msr.h>
#include <cpu/p6/mtrr.h>
#include <cpu/k7/mtrr.h>
@ -43,120 +44,6 @@ static unsigned int mtrr_msr[] = {
MTRRfix4K_E0000_MSR, MTRRfix4K_E8000_MSR, MTRRfix4K_F0000_MSR, MTRRfix4K_F8000_MSR,
};
#ifndef HAVE_MTRR_TABLE
/* We want to cache memory as efficiently as possible.
*/
#define MTRR_TYPE_RAM MTRR_TYPE_WRBACK
/* We can't use Write Combining on a legacy frame buffer because
* it is incompatible with EGA 16 color video modes...
*/
#define MTRR_TYPE_FB MTRR_TYPE_UNCACHABLE
/* For areas that are supposed to cover roms it makes no
* sense to cache writes.
*/
#define MTRR_TYPE_ROM MTRR_TYPE_WRPROT
#ifdef MEMORY_HOLE
#define RAM MTRR_TYPE_RAM
#define FB MTRR_TYPE_FB
#define ROM MTRR_TYPE_ROM
#else
#define RAM MTRR_TYPE_RAM
#define FB MTRR_TYPE_RAM
#define ROM MTRR_TYPE_RAM
#endif /* MEMORY_HOLE */
#ifdef MTRR_ONLY_TOP_64K_FLASH
// This is for boards that only support flash in low memory at 0xf0000
// and above, such as the technoland sbc 710. This type of board
// is so common that we put it here instead of in the sbc710 mainboard.c
static unsigned char fixed_mtrr_values[][4] = {
/* MTRRfix64K_00000_MSR, defines memory range from 0KB to 512 KB, each byte cover 64KB area */
{RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM},
/* MTRRfix16K_80000_MSR, defines memory range from 512KB to 640KB, each byte cover 16KB area */
{RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM},
/* MTRRfix16K_A0000_MSR, defines memory range from A0000 to C0000, each byte cover 16KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_C0000_MSR, defines memory range from C0000 to C8000, each byte cover 4KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_C8000_MSR, defines memory range from C8000 to D0000, each byte cover 4KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_D0000_MSR, defines memory range from D0000 to D8000, each byte cover 4KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_D8000_MSR, defines memory range from D8000 to E0000, each byte cover 4KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_E0000_MSR, defines memory range from E0000 to E8000, each byte cover 4KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_E8000_MSR, defines memory range from E8000 to F0000, each byte cover 4KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_F0000_MSR, defines memory range from F0000 to F8000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_F8000_MSR, defines memory range from F8000 to 100000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
};
#else
static unsigned char fixed_mtrr_values[][4] = {
/* MTRRfix64K_00000_MSR, defines memory range from 0KB to 512 KB, each byte cover 64KB area */
{RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM},
/* MTRRfix16K_80000_MSR, defines memory range from 512KB to 640KB, each byte cover 16KB area */
{RAM, RAM, RAM, RAM}, {RAM, RAM, RAM, RAM},
/* MTRRfix16K_A0000_MSR, defines memory range from A0000 to C0000, each byte cover 16KB area */
{FB, FB, FB, FB}, {FB, FB, FB, FB},
/* MTRRfix4K_C0000_MSR, defines memory range from C0000 to C8000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_C8000_MSR, defines memory range from C8000 to D0000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_D0000_MSR, defines memory range from D0000 to D8000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_D8000_MSR, defines memory range from D8000 to E0000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_E0000_MSR, defines memory range from E0000 to E8000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_E8000_MSR, defines memory range from E8000 to F0000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_F0000_MSR, defines memory range from F0000 to F8000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
/* MTRRfix4K_F8000_MSR, defines memory range from F8000 to 100000, each byte cover 4KB area */
{ROM, ROM, ROM, ROM}, {ROM, ROM, ROM, ROM},
};
#endif
#undef FB
#undef RAM
#undef ROM
#undef MTRR_TYPE_RAM
#undef MTRR_TYPE_FB
#undef MTRR_TYPE_ROM
#else
extern unsigned char fixed_mtrr_values[][4];
#endif
static void intel_enable_fixed_mtrr(void)
{
@ -176,24 +63,25 @@ static void intel_enable_var_mtrr(void)
wrmsr(MTRRdefType_MSR, low, high);
}
/* setting fixed mtrr, you can do some experiments with different memory type
defined in the table "fixed_mtrr_values" */
static void intel_set_fixed_mtrr(void)
{
unsigned int i;
unsigned long low, high;
for (i = 0; i < arraysize(mtrr_msr); i++) {
low = *(unsigned long *) fixed_mtrr_values[i*2];
high = *(unsigned long *) fixed_mtrr_values[i*2+1];
wrmsr(mtrr_msr[i], low, high);
}
}
/* setting variable mtrr, comes from linux kernel source */
static void intel_set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type)
static void intel_set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek, unsigned char type)
{
unsigned int tmp;
unsigned long base_high, base_low;
unsigned long mask_high, mask_low;
base_high = basek >> 22;
base_low = basek << 10;
if (sizek < 4*1024*1024) {
mask_high = 0x0F;
mask_low = ~((sizek << 10) -1);
}
else {
mask_high = 0x0F & (~((sizek >> 22) -1));
mask_low = 0;
}
if (reg >= 8)
return;
@ -208,14 +96,14 @@ static void intel_set_var_mtrr(unsigned int reg, unsigned long base, unsigned lo
"movl %0, %%cr0\n\t"
"wbinvd\n\t":"=r" (tmp)::"memory");
if (size == 0) {
if (sizek == 0) {
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
wrmsr (MTRRphysMask_MSR (reg), 0, 0);
} else {
/* Bit 32-35 of MTRRphysMask should be set to 1 */
wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0x0F);
wrmsr (MTRRphysBase_MSR(reg), base_low | type, base_high);
wrmsr (MTRRphysMask_MSR(reg), mask_low | 0x800, mask_high);
}
// turn cache back on.
@ -262,7 +150,7 @@ void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsi
}
/* fms: find most sigificant bit set, stolen from Linux Kernel Source. */
static __inline__ unsigned int fms(unsigned int x)
static inline unsigned int fms(unsigned int x)
{
int r;
@ -273,6 +161,18 @@ static __inline__ unsigned int fms(unsigned int x)
return r;
}
/* fms: find least sigificant bit set */
static inline unsigned int fls(unsigned int x)
{
int r;
__asm__("bsfl %1,%0\n\t"
"jnz 1f\n\t"
"movl $32,%0\n"
"1:" : "=r" (r) : "g" (x));
return r;
}
/* setting up variable and fixed mtrr
*
* From Intel Vol. III Section 9.12.4, the Range Size and Base Alignment has some kind of requirement:
@ -299,81 +199,152 @@ static __inline__ unsigned int fms(unsigned int x)
#define OS_MTRRS 2
#define MTRRS (BIOS_MTRRS + OS_MTRRS)
void setup_mtrrs(unsigned long ramsizeK)
static void set_fixed_mtrrs(unsigned int first, unsigned int last, unsigned char type)
{
unsigned int reg = 0;
unsigned long range_wb, range_uc;
unsigned long rambase;
unsigned long romendK;
printk_debug("\n");
rambase = 0;
while (ramsizeK != 0 && reg < BIOS_MTRRS) {
post_code(0x60 + reg);
range_wb = 1 << (fms(ramsizeK - 1) + 1);
range_uc = range_wb - ramsizeK;
if ((range_uc == 0) || ((ramsizeK % range_uc) == 0)) {
printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type: WB\n",
reg, rambase >> 10, range_wb >> 10);
intel_set_var_mtrr(reg++, rambase * 1024, range_wb * 1024,
MTRR_TYPE_WRBACK);
rambase += ramsizeK;
if (range_uc) {
printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type: UC\n",
reg, rambase >> 10, range_uc >> 10);
intel_set_var_mtrr(reg++, rambase * 1024, range_uc * 1024,
MTRR_TYPE_UNCACHABLE);
unsigned int i;
unsigned int fixed_msr = NUM_FIXED_RANGES >> 3;
unsigned long low, high;
low = high = 0; /* Shut up gcc */
for(i = first; i < last; i++) {
/* When I switch to a new msr read it in */
if (fixed_msr != i >> 3) {
/* But first write out the old msr */
if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
wrmsr(mtrr_msr[fixed_msr], low, high);
}
ramsizeK = 0; /* effectivly a break */
fixed_msr = i>>3;
rdmsr(mtrr_msr[fixed_msr], low, high);
}
if ((i & 7) < 4) {
low &= ~(0xff << ((i&3)*8));
low |= type << ((i&3)*8);
} else {
range_wb >>= 1;
printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type: WB\n",
reg, rambase >> 10, range_wb >> 10);
intel_set_var_mtrr(reg++, rambase * 1024, range_wb * 1024,
MTRR_TYPE_WRBACK);
rambase += range_wb;
ramsizeK -= range_wb;
high &= ~(0xff << ((i&3)*8));
high |= type << ((i&3)*8);
}
}
printk_debug("DONE variable MTRRs\n");
#if defined(XIP_ROM_SIZE) && defined(XIP_ROM_BASE)
#if XIP_ROM_SIZE < 4096
#error XIP_ROM_SIZE must be at least 4K
#endif
#if XIP_ROM_SIZE & (XIP_ROM_SIZE -1)
#error XIP_ROM_SIZE must be a power of two
#endif
#if XIP_ROM_BASE & (XIP_ROM_SIZE -1)
#error XIP_ROM_BASE must be a multiple of XIP_ROM_SIZE
#endif
/* I assume that XIP_ROM_SIZE is a power of two
* and that XIP_ROM_BASE is power of tow aligned.
*/
romendK = (XIP_ROM_BASE + XIP_ROM_SIZE) >>10;
if ((reg < BIOS_MTRRS) &&
((XIP_ROM_BASE > rambase) || (romendK > rambase))) {
intel_set_var_mtrr(reg++, XIP_ROM_BASE, XIP_ROM_SIZE,
MTRR_TYPE_WRPROT);
/* Write out the final msr */
if (fixed_msr < (NUM_FIXED_RANGES >> 3)) {
wrmsr(mtrr_msr[fixed_msr], low, high);
}
#endif /* XIP_ROM_SIZE && XIP_ROM_BASE */
}
static unsigned fixed_mtrr_index(unsigned long addrk)
{
unsigned index;
index = (addrk - 0) >> 6;
if (index >= 8) {
index = ((addrk - 8*64) >> 4) + 8;
}
if (index >= 24) {
index = ((addrk - (8*64 + 16*16)) >> 2) + 24;
}
if (index > NUM_FIXED_RANGES) {
index = NUM_FIXED_RANGES;
}
return index;
}
static unsigned int range_to_mtrr(unsigned int reg,
unsigned long range_startk, unsigned long range_sizek)
{
if (!range_sizek || (reg >= BIOS_MTRRS)) {
return reg;
}
while(range_sizek) {
unsigned long max_align, align;
unsigned long sizek;
/* Compute the maximum size I can make a range */
max_align = fls(range_startk);
align = fms(range_sizek);
if (align > max_align) {
align = max_align;
}
sizek = 1 << align;
printk_debug("Setting variable MTRR %d, base: %4dMB, range: %4dMB, type WB\n",
reg, range_startk >>10, sizek >> 10);
intel_set_var_mtrr(reg++, range_startk, sizek, MTRR_TYPE_WRBACK);
range_startk += sizek;
range_sizek -= sizek;
if (reg >= BIOS_MTRRS)
break;
}
return reg;
}
void setup_mtrrs(struct mem_range *mem)
{
/* Try this the simple way of incrementally adding together
* mtrrs. If this doesn't work out we can get smart again
* and clear out the mtrrs.
*/
struct mem_range *memp;
unsigned long range_startk, range_sizek;
unsigned int reg;
printk_debug("\n");
/* Initialized the fixed_mtrrs to uncached */
printk_debug("Setting fixed MTRRs(%d-%d) type: UC\n",
0, NUM_FIXED_RANGES);
set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHABLE);
/* Now see which of the fixed mtrrs cover ram.
*/
for(memp = mem; memp->sizek; memp++) {
unsigned int start_mtrr;
unsigned int last_mtrr;
start_mtrr = fixed_mtrr_index(memp->basek);
last_mtrr = fixed_mtrr_index(memp->basek + memp->sizek);
if (start_mtrr >= NUM_FIXED_RANGES) {
break;
}
printk_debug("Setting fixed MTRRs(%d-%d) type: WB\n",
start_mtrr, last_mtrr);
set_fixed_mtrrs(start_mtrr, last_mtrr, MTRR_TYPE_WRBACK);
}
printk_debug("DONE fixed MTRRs\n");
/* Cache as many memory areas as possible */
/* FIXME is there an algorithm for computing the optimal set of mtrrs?
* In some cases it is definitely possible to do better.
*/
range_startk = 0;
range_sizek = 0;
reg = 0;
for (memp = mem; memp->sizek; memp++) {
/* See if I can merge with the last range
* Either I am below 1M and the fixed mtrrs handle it, or
* the ranges touch.
*/
if ((memp->basek <= 1024) || (range_startk + range_sizek == memp->basek)) {
unsigned long endk = memp->basek + memp->sizek;
range_sizek = endk - range_startk;
continue;
}
/* Write the range mtrrs */
if (range_sizek != 0) {
reg = range_to_mtrr(reg, range_startk, range_sizek);
range_startk = 0;
range_sizek = 0;
if (reg >= BIOS_MTRRS)
break;
}
/* Allocate an msr */
range_startk = memp->basek;
range_sizek = memp->sizek;
}
/* Write the last range */
reg = range_to_mtrr(reg, range_startk, range_sizek);
printk_debug("DONE variable MTRRs\n");
printk_debug("Clear out the extra MTRR's\n");
/* Clear out the extra MTRR's */
while(reg < MTRRS) {
intel_set_var_mtrr(reg++, 0, 0, 0);
}
printk_debug("call intel_set_fixed_mtrr()\n");
intel_set_fixed_mtrr();
/* enable fixed MTRR */
printk_debug("call intel_enable_fixed_mtrr()\n");
intel_enable_fixed_mtrr();
printk_debug("call intel_enable_var_mtrr()\n");
intel_enable_var_mtrr();
printk_debug("Leave " __FUNCTION__ "\n");
printk_debug("Leave %s\n", __FUNCTION__);
}

View file

@ -3,10 +3,12 @@
#include <boot/linuxbios_tables.h>
struct mem_range;
/* This file holds function prototypes for building the linuxbios table. */
unsigned long write_linuxbios_table(
unsigned long *processor_map,
unsigned long totalram,
struct mem_range *ram,
unsigned long low_table_start, unsigned long low_table_end,
unsigned long rom_table_start, unsigned long rom_table_end);
@ -17,7 +19,7 @@ struct lb_record *lb_next_record(struct lb_record *rec);
struct lb_record *lb_new_record(struct lb_header *header);
struct lb_memory *lb_memory(struct lb_header *header);
void lb_memory_range(struct lb_memory *mem,
uint32_t type, unsigned long start, unsigned long size);
uint32_t type, unsigned long startk, unsigned long sizek);
struct lb_mainboard *lb_mainboard(struct lb_header *header);
unsigned long lb_table_fini(struct lb_header *header);

View file

@ -61,8 +61,9 @@ struct lb_memory_range {
uint64_t start;
uint64_t size;
uint32_t type;
#define LB_MEM_RAM 1
#define LB_MEM_RESERVED 2
#define LB_MEM_RAM 1 /* Memory anyone can use */
#define LB_MEM_RESERVED 2 /* Don't use this memory region */
#define LB_MEM_TABLE 16 /* Ram configuration tables are kept in */
};
@ -88,7 +89,21 @@ struct lb_mainboard {
uint8_t strings[0];
};
#define LB_TAG_VERSION 0x0004
#define LB_TAG_EXTRA_VERSION 0x0005
#define LB_TAG_BUILD 0x0006
#define LB_TAG_COMPILE_TIME 0x0007
#define LB_TAG_COMPILE_BY 0x0008
#define LB_TAG_COMPILE_HOST 0x0009
#define LB_TAG_COMPILE_DOMAIN 0x000a
#define LB_TAG_COMPILER 0x000b
#define LB_TAG_LINKER 0x000c
#define LB_TAG_ASSEMBLER 0x000d
struct lb_string {
uint32_t tag;
uint32_t size;
uint8_t string[0];
};
/* The following structures are for the cmos definitions table */
#define LB_TAG_CMOS_OPTION_TABLE 200

View file

@ -1,19 +1,21 @@
#ifndef CPU_CPUFIXUP_H
#define CPU_CPUFIXUP_H
struct mem_range;
#include <cpu/k7/cpufixup.h>
#include <cpu/p6/cpufixup.h>
#ifdef CPU_FIXUP
# if defined(k7)
# define cpufixup(totalram) k7_cpufixup(totalram)
# define cpufixup(mem) k7_cpufixup(mem)
# elif defined(i786)
# define cpufixup(totalram) p6_cpufixup(totalram)
# define cpufixup(mem) p6_cpufixup(mem)
# elif defined(i686)
# define cpufixup(totalram) p6_cpufixup(totalram)
# define cpufixup(mem) p6_cpufixup(mem)
# endif
#else
# define cpufixup(totalram) do {} while(0)
# define cpufixup(mem) do {} while(0)
#endif
#endif /* CPU_CPUFIXUP_H */

View file

@ -1,6 +1,6 @@
#ifndef CPU_K7_CPUFIXUP_H
#define CPU_K7_CPUFIXUP_H
void k7_cpufixup(unsigned long totalram);
void k7_cpufixup(struct mem_range *mem);
#endif /* CPU_K7_CPUFIXUP_H */

View file

@ -5,6 +5,6 @@
#define CPU_FIXUP
#endif
void p6_cpufixup(unsigned long totalram);
void p6_cpufixup(struct mem_range *mem);
#endif /* CPU_P6_CPUFIXUP_H */

View file

@ -35,7 +35,8 @@
void set_var_mtrr(unsigned int reg, unsigned long base, unsigned long size, unsigned char type);
#if defined(INTEL_PPRO_MTRR)
void setup_mtrrs(unsigned long ramsizeK);
struct mem_range;
void setup_mtrrs(struct mem_range *mem);
#endif
#endif /* ASSEMBLY */

11
src/include/mem.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef MEM_H
#define MEM_H
struct mem_range {
unsigned long basek;
unsigned long sizek;
};
/* mem_range arrays are non-overlapping, in ascending order and null terminated */
#endif /* MEM_H */

View file

@ -0,0 +1,6 @@
#ifndef AMD76X_H
#define AMD76X_H
void amd76x_setup_pci_arbiter(void);
#endif /* AMD76X_H */

View file

@ -1,6 +1,7 @@
#ifndef PART_SIZERAM_H
#define PART_SIZERAM_H
unsigned long sizeram(void);
struct mem_rang;
struct mem_range *sizeram(void);
#endif /* PART_SIZERAM_H */

View file

@ -10,18 +10,22 @@
//extern inline int strlen(char *src) { int i = 0; while (*src++) i++; return i;}
static inline size_t strnlen(const char *src, size_t max) {
int i = 0;
if (max<0) {
while (*src++)
i++;
return i;
}
else {
while ((*src++) && (i < max))
i++;
return i;
}
static inline size_t strnlen(const char *src, size_t max)
{
size_t i = 0;
while((*src++) && (i < max)) {
i++;
}
return i;
}
static inline size_t strlen(const char *src)
{
size_t i = 0;
while(*src++) {
i++;
}
return i;
}
extern void *memcpy(void *dest, const void *src, size_t n);

22
src/include/version.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef VERSION_H
#define VERSION_H
/* Motherboard Information */
extern const char mainboard_vendor[];
extern const char mainboard_part_number[];
/* LinuxBIOS Version */
extern const char linuxbios_version[];
extern const char linuxbios_extra_version[];
extern const char linuxbios_build[];
/* When LinuxBIOS was compiled */
extern const char linuxbios_compile_time[];
extern const char linuxbios_compile_by[];
extern const char linuxbios_compile_host[];
extern const char linuxbios_compile_domain[];
extern const char linuxbios_compiler[];
extern const char linuxbios_linker[];
extern const char linuxbios_assembler[];
#endif /* VERSION_H */

View file

@ -16,4 +16,7 @@ object do_inflate.o
object floppy_subr.o BOOT_FLOPPY
object delay.o
object fallback_boot.o HAVE_FALLBACK_BOOT
object compute_ip_checksum.o
object compute_ip_checksum.o
object version.o
# Force version.o to recompile every time
makedefine .PHONY : version.o

View file

@ -3,54 +3,34 @@
unsigned long compute_ip_checksum(void *addr, unsigned long length)
{
uint16_t *ptr;
uint8_t *ptr;
volatile union {
uint8_t byte[2];
uint16_t word;
} value;
unsigned long sum;
unsigned long len;
unsigned long laddr;
/* compute an ip style checksum */
laddr = (unsigned long )addr;
unsigned long i;
/* In the most straight forward way possible,
* compute an ip style checksum.
*/
sum = 0;
if (laddr & 1) {
uint16_t buffer;
unsigned char *ptr;
/* copy the first byte into a 2 byte buffer.
* This way automatically handles the endian question
* of which byte (low or high) the last byte goes in.
*/
buffer = 0;
ptr = addr;
memcpy(&buffer, ptr, 1);
sum += buffer;
if (sum > 0xFFFF)
sum -= 0xFFFF;
length -= 1;
addr = ptr +1;
}
len = length >> 1;
ptr = addr;
while (len--) {
sum += *(ptr++);
if (sum > 0xFFFF)
sum -= 0xFFFF;
for(i = 0; i < length; i++) {
unsigned long value;
value = ptr[i];
if (i & 1) {
value <<= 8;
}
/* Add the new value */
sum += value;
/* Wrap around the carry */
if (sum > 0xFFFF) {
sum = (sum + (sum >> 16)) & 0xFFFF;
}
}
addr = ptr;
if (length & 1) {
uint16_t buffer;
unsigned char *ptr;
/* copy the last byte into a 2 byte buffer.
* This way automatically handles the endian question
* of which byte (low or high) the last byte goes in.
*/
buffer = 0;
ptr = addr;
memcpy(&buffer, ptr, 1);
sum += buffer;
if (sum > 0xFFFF)
sum -= 0xFFFF;
}
return (~sum) & 0xFFFF;
value.byte[0] = sum & 0xff;
value.byte[1] = (sum >> 8) & 0xff;
return (~value.word) & 0xFFFF;
}
unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)

View file

@ -139,11 +139,11 @@ void pci_get_size(struct pci_dev *dev, unsigned long reg, unsigned long addr)
// This incidentally catches the common case where registers
// read back as 0 for both address and size.
if (addr == size) {
printk_debug(__FUNCTION__
printk_spew(__FUNCTION__
"dev_fn 0x%x, register %d, read-only"
" SO, ignoring it\n",
dev->devfn, reg);
printk_debug("addr was 0x%x, size was 0x%x\n",addr,size);
printk_spew("addr was 0x%x, size was 0x%x\n",addr,size);
type = 0;
size = 0;
}

View file

@ -21,7 +21,7 @@ static char rcsid[] = "$Id$";
#define ONEMEG (1 << 20)
#define PCI_MEM_START 0x80000000
#define PCI_MEM_START 0xC0000000
#define PCI_IO_START 0x1000
// historical functions, sometimes very useful.

View file

@ -1,3 +1,5 @@
#include <mem.h>
#include <part/sizeram.h>
#include <pci.h>
#include <printk.h>
@ -25,7 +27,7 @@ void refresh_set(int turn_it_on)
// printk_info( __FUNCTION__ "refresh is now 0x%lx\n", ref);
}
// FIX ME!
unsigned long sizeram()
static unsigned long __sizeram(void)
{
extern void cache_disable(void), cache_enable(void);
int i;
@ -177,7 +179,21 @@ unsigned long sizeram()
cache_enable();
return 0; //64*1024*1024;
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
#ifdef HAVE_FRAMEBUFFER

View file

@ -1,14 +1,23 @@
#include <mem.h>
#include <pci.h>
#include <cpu/p5/io.h>
#include <part/sizeram.h>
unsigned long sizeram(void)
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
u32 size;
/* Use the PCI top memory register */
pcibios_read_config_dword(0, 0, 0x9c, &size);
/* Convert size in bytes to size in K */
size = size >> 10;
return size;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = size - mem[1].basek;
mem[2].basek = 0;
mem[2].sizke = 0;
return &mem;
}

View file

@ -1803,7 +1803,7 @@ spd_set_dram_timing_out:
* Arguments: %bl device on the smbus to read from
* %esi an initially zeroed copy of the
* DRAM mode register.
* %ebp Pointer to infomration that varies by memory bus speed
* %ebp Pointer to information that varies by memory bus speed
*
* Results: cf clear
* %esi updated with dimm with setting

View file

@ -1,8 +1,11 @@
#include <mem.h>
#include <part/sizeram.h>
#include <pci.h>
unsigned long sizeram()
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
/*
* Code for the BX/GX and TX are almost the same
*/
@ -28,7 +31,13 @@ unsigned long sizeram()
totalmem = 0x20000000UL;
}
return totalmem;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = totalmem - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}

View file

@ -1,8 +1,11 @@
#include <mem.h>
#include <part/sizeram.h>
#include <pci.h>
unsigned long sizeram()
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
/*
* This is written for BX but should work also for GX.
*/
@ -24,7 +27,14 @@ unsigned long sizeram()
totalmem = 0x80000000UL;
}
return totalmem;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = totalmem - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}

View file

@ -1,3 +1,5 @@
#include <mem.h>
#include <part/sizeram.h>
#include <pci.h>
#include <cpu/p5/io.h>
#include <printk.h>
@ -29,7 +31,7 @@ dumpramregs(struct pci_dev *pcidev)
}
unsigned long sizeram()
struct mem_range *sizeram(void)
{
/*
* This is written for BX but should work also for GX.
@ -53,7 +55,13 @@ unsigned long sizeram()
}
dumpramregs(pcidev);
return totalmem;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = totalmem - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}

View file

@ -6,6 +6,8 @@
*/
#include <mem.h>
#include <part/sizeram.h>
#include <pci.h>
#include <printk.h>
@ -19,8 +21,9 @@ static int DRP_sizetbl[] = {
256, 256, 256, 512
};
unsigned long sizeram()
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
unsigned long totalmem, curmem;
unsigned char regval;
@ -46,7 +49,13 @@ unsigned long sizeram()
printk_info("DIMM2 - size = %ldM\n", curmem );
totalmem += curmem;
return totalmem * 1024;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = totalmem*1024 - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}

View file

@ -3,11 +3,14 @@
Intel 830 sizing.
*/
#include <mem.h>
#include <part/sizeram.h>
#include <pci.h>
#include <printk.h>
unsigned long sizeram()
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
unsigned long totalmem;
unsigned char regval;
@ -23,7 +26,14 @@ unsigned long sizeram()
totalmem += regval * 32;
}
return totalmem * 1024;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = totalmem*1024 - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}

View file

@ -1,9 +1,10 @@
#include <mem.h>
#include <pci.h>
#include <arch/io.h>
#include <part/sizeram.h>
#include <printk.h>
unsigned long sizeram(void)
struct mem_range *sizeram(void)
{
unsigned long size;
unsigned short word;
@ -13,6 +14,12 @@ unsigned long sizeram(void)
pcibios_read_config_word(0, 0, 0xc4, &word);
/* Convert size in 64K bytes to size in K bytes */
size = word << 6;
return size;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = size - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}

View file

@ -1,18 +1,45 @@
#include <mem.h>
#include <pci.h>
#include <arch/io.h>
#include <part/sizeram.h>
#include <printk.h>
unsigned long sizeram(void)
struct mem_range *sizeram(void)
{
unsigned long size;
unsigned short word;
static struct mem_range mem[4];
uint16_t tolm, remapbase, remaplimit;
uint8_t drb;
/* Read TOLM */
/* How should we handle > 4GB of ram? */
pcibios_read_config_word(0, 0, 0xc4, &word);
/* Convert size in 128K bytes to size in K bytes */
size = word << 5;
return size;
/* FIXME do some of the configuration here instead of
* just reading it all out, and reporting it.
*/
/* Read the ram configruation registers */
pcibios_read_config_word(0, 0, 0xc4, &tolm);
pcibios_read_config_word(0, 0, 0xc6, &remapbase);
remapbase &= 0x1FF;
pcibios_read_config_word(0, 0, 0xc8, &remaplimit);
remaplimit &= 0x1FF;
pcibios_read_config_byte(0, 0, 0x67, &drb);
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 768;
/* Convert size in 64K bytes to size in K bytes */
mem[1].sizek = (tolm << 6) - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
if ((drb << 16) > (tolm << 6)) {
mem[2].basek = 4096*1024;
mem[2].sizek = (drb << 16) - mem[2].basek;
/* I know that the remap window always immediately follows
* the real top of memory.
*/
if (remapbase < remaplimit) {
mem[2].sizek = (remaplimit << 16) - mem[2].basek;
}
}
mem[3].basek = 0;
mem[3].sizek = 0;
return &mem;
}

View file

@ -1,9 +1,12 @@
#include <mem.h>
#include <part/sizeram.h>
#include <pci.h>
#include <cpu/p5/io.h>
#include <printk.h>
unsigned long sizeram()
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
//unsigned long totalmemKB = 1024*1024;
struct pci_dev *pcidev;
unsigned long totalmemKB = 0 ,memfound = 0;
@ -64,9 +67,14 @@ unsigned long sizeram()
pci_read_config_byte(pcidev,(0x80+i),&value);
}
}
return totalmemKB;
//return 1024*1024;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = totalmemKB - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}

View file

@ -6,6 +6,8 @@
Do chipset setup for a National Semiconductor GX1 CPU.
*/
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pci.h>
#include <pci_ids.h>
@ -58,8 +60,9 @@ static unsigned long adjust_video_memory(unsigned long mem_size)
return mem_size;
}
unsigned long sizeram()
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
u32 mem_bank_cfg;
unsigned mem_size;
@ -71,7 +74,13 @@ unsigned long sizeram()
mem_size = adjust_video_memory(mem_size);
return mem_size;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = mem_size - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}
/*

View file

@ -1,9 +1,11 @@
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pci.h>
#include <pciconf.h>
unsigned long sizeram()
static unsigned long __sizeram(void)
{
unsigned long totalmem;
unsigned char bank, mem, prevmem;
@ -52,13 +54,21 @@ unsigned long sizeram()
return totalmem;
}
/*
unsigned long sizeram()
struct mem_range *sizeram(void)
{
return 0;
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
*/
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()

View file

@ -1,9 +1,11 @@
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pci.h>
#include <pciconf.h>
unsigned long sizeram()
static unsigned long __sizeram(void)
{
unsigned long totalmem;
unsigned char bank, mem, prevmem;
@ -52,13 +54,21 @@ unsigned long sizeram()
return totalmem;
}
/*
unsigned long sizeram()
struct mem_range *sizeram(void)
{
return 0;
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
*/
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()

View file

@ -5,6 +5,8 @@
Do chipset setup for a National Semiconductor SCx200 CPU.
*/
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pci.h>
#include <pci_ids.h>
@ -26,8 +28,9 @@ static unsigned calc_dimm(int index, unsigned cfg)
}
}
unsigned long sizeram()
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
u32 mem_bank_cfg;
unsigned mem_size;
@ -37,7 +40,13 @@ unsigned long sizeram()
mem_size += calc_dimm(0, mem_bank_cfg);
mem_size += calc_dimm(1, mem_bank_cfg >> 16);
return mem_size;
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = mem_size - mem[1].basek;
mem[2].basek = 0;
mem[2].sizek = 0;
return &mem;
}
/*

View file

@ -11,6 +11,8 @@ static char rcsid[] =
#endif
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pciconf.h>
#include <subr.h>
@ -37,7 +39,7 @@ const static int ramsizes[16] =
#define SIS630_BANK1 0x61
#define SIS630_BANK2 0x62
#define SIS630_DIMM_LOCATION_FOR_SMA 0x65
unsigned long sizeram()
static unsigned long __sizeram(void)
{
struct pci_dev *pcidev;
unsigned int dimm_slot, dimm_reg, sides;
@ -95,6 +97,22 @@ unsigned long sizeram()
return total_size;
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()
{

View file

@ -11,6 +11,8 @@ static char rcsid[] =
#endif
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pciconf.h>
#include <subr.h>
@ -37,7 +39,7 @@ const static int ramsizes[16] =
#define SIS630_BANK1 0x61
#define SIS630_BANK2 0x62
#define SIS630_DIMM_LOCATION_FOR_SMA 0x65
unsigned long sizeram()
static unsigned long __sizeram(void)
{
struct pci_dev *pcidev;
unsigned int dimm_slot, dimm_reg, sides;
@ -92,6 +94,23 @@ unsigned long sizeram()
return total_size;
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()
{

View file

@ -11,6 +11,8 @@ static char rcsid[] =
#endif
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pciconf.h>
#include <subr.h>
@ -37,7 +39,7 @@ const static int ramsizes[16] =
#define SIS630_BANK1 0x61
#define SIS630_BANK2 0x62
#define SIS630_DIMM_LOCATION_FOR_SMA 0x65
unsigned long sizeram()
static unsigned long __sizeram(void)
{
struct pci_dev *pcidev;
unsigned int dimm_slot, dimm_reg, sides;
@ -92,6 +94,23 @@ unsigned long sizeram()
return total_size;
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()
{

View file

@ -23,6 +23,8 @@
*
*/
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pciconf.h>
#include <subr.h>
@ -49,8 +51,7 @@ const static int ramsizes[16] =
#define SIS635_BANK1 0x61
#define SIS635_BANK2 0x62
#define SIS635_BANK3 0x63
unsigned
long sizeram()
static unsigned long __sizeram(void)
{
struct pci_dev *pcidev;
unsigned int dimm_slot, dimm_reg, sides;
@ -87,6 +88,24 @@ long sizeram()
return total_size;
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()
{

View file

@ -1,6 +1,5 @@
/*
<<<<<<< northbridge.c
* southbridge.c: Norththbridge Initialization For SiS 730
* northbridge.c: Norththbridge Initialization For SiS 730
*
* Copyright 2002 Silicon Integrated Systems Corp.
*
@ -28,6 +27,8 @@ static char rcsid[] =
#endif
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pciconf.h>
#include <subr.h>
@ -56,7 +57,7 @@ const static int ramsizes[16] =
#define SIS630_DIMM_LOCATION_FOR_SMA 0x65
#define MAX_DIMM_SLOTS 3
unsigned long sizeram()
static unsigned long __sizeram(void)
{
struct pci_dev *pcidev;
unsigned int dimm_slot, dimm_reg, sides;
@ -111,6 +112,22 @@ unsigned long sizeram()
return total_size;
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()
{

View file

@ -23,6 +23,8 @@
*
*/
#include <mem.h>
#include <part/sizeram.h>
#include <printk.h>
#include <pciconf.h>
#include <subr.h>
@ -49,8 +51,7 @@ const static int ramsizes[16] =
#define SIS735_BANK1 0x61
#define SIS735_BANK2 0x62
#define SIS735_BANK3 0x63
unsigned
long sizeram()
static unsigned long __sizeram(void)
{
struct pci_dev *pcidev;
unsigned int dimm_slot, dimm_reg, sides;
@ -87,6 +88,22 @@ long sizeram()
return total_size;
}
struct mem_range *sizeram(void)
{
static struct mem_range mem[3];
mem[0].basek = 0;
mem[0].sizek = 640;
mem[1].basek = 1024;
mem[1].sizek = __sizeram();
mem[2].basek = 0;
mem[2].sizek = 0;
if (mem[1].sizek == 0) {
mem[1].sizek = 64*1024;
}
mem[1].sizek -= mem[1].basek;
return &mem;
}
#ifdef HAVE_FRAMEBUFFER
void framebuffer_on()
{

View file

@ -236,7 +236,7 @@ int get_option(void *dest, char *name)
}
}
if(!found) {
printk_err("ERR: No cmos option '%s'\n", name);
printk_err("ERROR: No cmos option '%s'\n", name);
return(-2);
}

View file

@ -12,36 +12,27 @@ dn_after: .string "After setting values: \r\n"
.previous
dumpnorth:
dumpnorth:
mov %esp, %ebp
CONSOLE_INFO_TX_STRING($dn_banner)
xorl %ecx, %ecx
1:
CONSOLE_INFO_TX_HEX32(%ecx)
CONSOLE_INFO_TX_CHAR($'-')
movl %ecx, %eax
CONSOLE_INFO_TX_HEX8(%cl)
CONSOLE_INFO_TX_CHAR($':')
CONSOLE_INFO_TX_CHAR($' ')
PCI_READ_CONFIG_DWORD
#if 0
CONSOLE_INFO_TX_HEX32(%eax)
#else
CONSOLE_INFO_TX_HEX8(%al)
2:
movl %ecx, %eax
PCI_READ_CONFIG_DWORD
shrl $8,%eax
PCI_READ_CONFIG_BYTE
CONSOLE_INFO_TX_HEX8(%al)
movl %ecx, %eax
PCI_READ_CONFIG_DWORD
shrl $16,%eax
CONSOLE_INFO_TX_HEX8(%al)
movl %ecx, %eax
PCI_READ_CONFIG_DWORD
shrl $24,%eax
CONSOLE_INFO_TX_HEX8(%al)
#endif
CONSOLE_INFO_TX_CHAR($' ')
incl %ecx
testb $0xf, %cl
jnz 2b
CONSOLE_INFO_TX_CHAR($'\r')
CONSOLE_INFO_TX_CHAR($'\n')
addl $0x4, %ecx
cmpl $256, %ecx
jne 1b
CONSOLE_INFO_TX_STRING($dn_done)

View file

@ -0,0 +1,24 @@
/* enable caching for 0 - 16M using a variable mtrr
* This should be all we need to get good performance out of LinuxBIOS.
*/
/* Disable the cache while we set up a new MTRR over memory */
movl %cr0, %eax
orl $0x40000000, %eax
movl %eax, %cr0
movl $0x200, %ecx /* mtrr[0] physical base register */
movl $0x00000000, %edx
movl $0x00000006, %eax
wrmsr
movl $0x201, %ecx /* mtrr[0] physical mask register */
movl $0x0000000f, %edx
movl $0xff000800, %eax
wrmsr
/* Reenable the cache now that the mtrr is set up */
movl %cr0, %eax
andl $0x9fffffff, %eax
movl %eax, %cr0

View file

@ -8,15 +8,14 @@ dump_spd_reg_dimm:
CONSOLE_DEBUG_TX_CHAR($'m')
CONSOLE_DEBUG_TX_CHAR($'m')
CONSOLE_DEBUG_TX_CHAR($' ')
movb %bl, %al
CALLSP(ttys0_tx_hex8)
CONSOLE_DEBUG_TX_HEX8(%bl)
CONSOLE_DEBUG_TX_CHAR($'\r')
CONSOLE_DEBUG_TX_CHAR($'\n')
dump_spd_reg_byte:
CALLSP(smbus_read_byte)
jz dump_spd_reg_next_dimm
CALLSP(ttys0_tx_hex8)
CONSOLE_DEBUG_TX_HEX8(%al)
CONSOLE_DEBUG_TX_CHAR($' ')
incb %bh
testb $0x0F, %bh

View file

@ -7,11 +7,14 @@ ram_4: .string "Ram4\r\n"
ram_5: .string "Ram5\r\n"
ram_6: .string "Ram6\r\n"
no_memory_str: .string "ERROR: No memory!"
crlf: .string "\r\n"
no_memory_str: .string "No memory!\r\n"
no_memory: CONSOLE_DEBUG_TX_STRING($no_memory_str)
1: hlt /* stick here.. */
no_memory: CONSOLE_ERR_TX_STRING($no_memory_str)
mem_stop:
CONSOLE_ERR_TX_STRING($crlf)
1:
hlt /* stick here.. */
jmp 1b
ram_initialize:

View file

@ -38,3 +38,16 @@
#define SMBUS_BUS 0
#define SMBUS_DEVFN ((0x1f << 3) + 3)
#define SMBUS_IO_BASE 0x1000
#define SMBHSTSTAT 0x0
#define SMBHSTCTL 0x2
#define SMBHSTCMD 0x3
#define SMBXMITADD 0x4
#define SMBHSTDAT0 0x5
#define SMBHSTDAT1 0x6
#define SMBBLKDAT 0x7
#define SMBTRNSADD 0x9
#define SMBSLVDATA 0xa
#define SMLINK_PIN_CTL 0xe
#define SMBUS_PIN_CTL 0xf

View file

@ -4,21 +4,6 @@
#include <southbridge/intel/82801.h>
#include "82801.h"
#define SMBUS_IO_BASE 0x1000
#define SMBHSTSTAT 0x0
#define SMBHSTCTL 0x2
#define SMBHSTCMD 0x3
#define SMBXMITADD 0x4
#define SMBHSTDAT0 0x5
#define SMBHSTDAT1 0x6
#define SMBBLKDAT 0x7
#define SMBTRNSADD 0x9
#define SMBSLVDATA 0xa
#define SMLINK_PIN_CTL 0xe
#define SMBUS_PIN_CTL 0xf
void smbus_setup(void)
{
pcibios_write_config_dword(SMBUS_BUS, SMBUS_DEVFN, 0x20, SMBUS_IO_BASE | 1);

View file

@ -1,65 +1,43 @@
/* Useful macros PCIBUS, and SMBUS functions for getting DRAM going. */
/* courtesy Eric Biederman of linuxnetworx.com */
/*
* Copyright (C) 2002 Eric Biederman
*/
#define CS_WRITE_BYTE(addr, byte) \
movl $addr, %eax ; \
movl $byte, %edx ; \
PCI_WRITE_CONFIG_BYTE
#define CS_WRITE_WORD(addr, word) \
movl $addr, %eax ; \
movl $word, %ecx ; \
PCI_WRITE_CONFIG_WORD
#define CS_WRITE_LONG(addr, dword) \
movl $addr, %eax ; \
movl $dword, %ecx ; \
PCI_WRITE_CONFIG_DWORD
#define DEVFN(device, function) (((device) << 3) + (function))
#ifndef CONFIG_ADDR
#define CONFIG_ADDR(bus,devfn,where) (((bus) << 16) | ((devfn) << 8) | (where))
#endif
#include "82801.h"
/* jump around these subrs */
jmp smbus_pcibus_end
/* generic SMB routines that work for many systems. The only one that might
* not work is the enable_smbus.
* you have to define PM_FUNCTION for this to work.
*/#define SMBUS_IO_BASE 0xf00
#define SMBHSTSTAT 0
#define SMBHSTCTL 2
#define SMBHSTCMD 3
#define SMBHSTADD 4
#define SMBHSTDAT0 5
#define SMBHSTDAT1 6
#define SMBBLKDAT 7
enable_smbus:
/* put the SMBUS at port 0xf00 */
CS_WRITE_LONG(PM_DEVFN+ 0x90, SMBUS_IO_BASE|1) /* iobase addr */
CS_WRITE_BYTE(PM_DEVFN + 0xd2, (0x4 << 1) | 1) /* smbus enable */
CS_WRITE_WORD(PM_DEVFN + 0x4, 1) /* iospace enable */
RET_LABEL(enable_smbus)
jmp smbus_end
/*
* Routine: setup_smbus
* Routine: smbus_setup
* Arguments: none
* Results: none
* Trashed: eax, edx
* Trashed: eax, edx, ecx
* Effects: The smbus is enabled
*/
setup_smbus:
xor %eax,%eax
movl $(SMBUS_IO_BASE +SMBHSTSTAT), %edx
outb %al, %dx
RET_LABEL(setup_smbus)
#define SMBUS_MEM_DEVICE_0 (0xa << 3)
#define SMBUS_MEM_DEVICE_1 (SMBUS_MEM_DEVICE_0 +1)
#define SMBUS_MEM_DEVICE_2 (SMBUS_MEM_DEVICE_0 +2)
#define SMBUS_MEM_DEVICE_3 (SMBUS_MEM_DEVICE_0 +3)
smbus_setup:
/* set smbus iobase */
movl $((SMBUS_DEVFN << 8) + 0x20), %eax
movl $(SMBUS_IO_BASE | 1), %ecx
PCI_WRITE_CONFIG_DWORD
/* Set smbus enable */
movl $((SMBUS_DEVFN << 8) + 0x40), %eax
movl $1, %edx
PCI_WRITE_CONFIG_BYTE
/* Set smbus iospace enable */
movl $((SMBUS_DEVFN << 8) + 0x4), %eax
movl $1, %ecx
PCI_WRITE_CONFIG_WORD
/* Diable interrupt generation */
movl $(SMBUS_IO_BASE + SMBHSTCTL), %edx
xorl %eax, %eax
outb %al, %dx
RET_LABEL(smbus_setup)
/*
* Routine: smbus_wait_until_ready
@ -69,10 +47,10 @@ setup_smbus:
* Effects: Upon return the smbus is ready to accept commands
*/
smbus_wait_until_ready:
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
1: inb %dx, %al
testb $1, %al
jnz 1b
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
1: inb %dx, %al
testb $1, %al
jnz 1b
RET_LABEL(smbus_wait_until_ready)
/*
@ -83,16 +61,16 @@ smbus_wait_until_ready:
* Effects: Upon return the smbus has completed it's most recent transation
*/
smbus_wait_until_done:
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
1: inb %dx, %al
testb $1, %al
jnz 1b
2: testb $0xFE, %al
jnz 3f
inb %dx, %al
testb $0xFE, %al
jz 2b
3: RET_LABEL(smbus_wait_until_done)
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
1: inb %dx, %al
testb $1, %al
jnz 1b
jmp 3f
2:
inb %dx, %al
3: testb $~((1<<6)|(1<<0)), %al
jz 2b
RET_LABEL(smbus_wait_until_done)
/*
@ -119,414 +97,65 @@ smbus_read_byte:
/* poll until the smbus is ready for commands */
CALL_LABEL(smbus_wait_until_ready)
/* clear any lingering errors, so that the transaction will run */
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
inb %dx, %al
outb %al, %dx
/* setup transaction */
/* disable interrupts */
movl $(SMBUS_IO_BASE + SMBHSTCTL), %edx
inb %dx, %al
andb $0xFE, %al
outb %al, %dx
/* set the device I'm talking to */
movl $(SMBUS_IO_BASE + SMBHSTADD), %edx
movb %bl /* device */, %al
shlb $1, %al
orb $1, %al
outb %al, %dx
movl $(SMBUS_IO_BASE + SMBXMITADD), %edx
movb %bl /* device */, %al
shlb $1, %al
orb $1, %al
outb %al, %dx
/* set the command address... */
movl $(SMBUS_IO_BASE + SMBHSTCMD), %edx
movb %bh /* address */, %al
outb %al, %dx
movl $(SMBUS_IO_BASE + SMBHSTCMD), %edx
movb %bh /* address */, %al
outb %al, %dx
/* clear the data byte */
movl $(SMBUS_IO_BASE + SMBHSTDAT0), %edx
xorl %eax, %eax
outb %al, %dx
/* setup for a byte data read */
movl $(SMBUS_IO_BASE + SMBHSTCTL), %edx
inb %dx, %al
andb $0xE3, %al
orb $(0x2 << 2), %al
outb %al, %dx
/* clear any lingering errors, so the transaction will run */
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
inb %dx, %al
outb %al, %dx
/* clear the data byte... */
movl $(SMBUS_IO_BASE + SMBHSTDAT0), %edx
xorl %eax, %eax
outb %al, %dx
/* start a byte read, with interrupts disabled */
movl $(SMBUS_IO_BASE + SMBHSTCTL), %edx
movl $((0x2 << 2) | (1 << 6)), %eax
outb %al, %dx
movl $(SMBUS_IO_BASE + SMBHSTCTL), %edx
inb %dx, %al
orb $0x40, %al
outb %al, %dx
/* poll for transaction completion */
CALL_LABEL(smbus_wait_until_done)
/* read the results and see if we succeded */
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
inb %dx, %al
testb $0x02, %al
jz 1f
movl $(SMBUS_IO_BASE + SMBHSTSTAT), %edx
inb %dx, %al
andb $~(1 << 6), %al /* Ignore the In Use Status... */
cmpb $0x02, %al
sete %al
testb %al, %al
jz 1f
movl $(SMBUS_IO_BASE + SMBHSTDAT0), %edx
inb %dx, %al
1:
RETSP
/* now for code to actually do the deed. Eric did such a good job that
* this stuff is basically generic.
*/
/*
* Routine: spd_set_drb
* Arguments: None
*
* Trashed: %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp, %eflags
* Effects: Uses serial presence detect to set the
* DRB registers which holds the ending memory address assigned
* to each DIMM.
* Notes: %ebp holds the currently detected end of memory.
* %ebx holds the configuration port & SMBUS_MEM_DEVICE for
* the current iteration through the loop.
* %edi holds the memory size for the first side of the DIMM.
* %esi holds the memory size for the second side of the DIMM.
* memory size is represent as a power of 2.
* An unset memory size is represented as -1 ie. 0xFFFFFFFF
*/
spd_set_drb:
xorl %ebp, %ebp /* clear the memory address */
movl $((DRAM_CONFIG_PORT << 16) |SMBUS_MEM_DEVICE_0), %ebx
spd_set_drb_loop_top:
// set -1 power-of-two for side 1 (called bank0 in most chipset docs)
xorl %edi, %edi
subl $1, %edi
// set -1 power-of-two for side 2 (called bank1 in most chipset docs)
xorl %esi, %esi
subl $1, %esi
movb $3, %bh /* rows */
CALLSP(smbus_read_byte)
// If it's zero, then we just set current %ebp into the row
// end register
jz 20f
andl $0xf, %eax
addl %eax, %edi
movb $4, %bh /* columns */
CALLSP(smbus_read_byte)
andl $0xf, %eax
addl %eax, %edi
movb $17, %bh /* banks */
CALLSP(smbus_read_byte)
andl $0xff, %eax
bsrl %eax, %ecx
addl %ecx, %edi
/* Get the module data width and convert it to a power of two */
movb $7, %bh /* (high byte) */
CALLSP(smbus_read_byte)
andl $0xff, %eax
movl %eax, %ecx
shll $8, %ecx
movb $6, %bh /* (low byte) */
CALLSP(smbus_read_byte)
andl $0xff, %eax
orl %eax, %ecx
bsrl %ecx, %eax
addl %eax, %edi
/* now I have the ram size in bits as a power of two (less 1) */
// It is less 1 since we started with -1 above.
// OK, BITS as power of two (but minus 1)
// So, e.g., 8 MB is 64 Mb, 64 Mb is 26 bits. Subtract
// (26-1) or 25
subl $25, %edi /* Make it multiples of 8MB */
/* side two */
movb $5, %bh /* number of physical banks */
CALLSP(smbus_read_byte)
cmp $1, %al
// it's only one bank
jbe 20f
// It's two banks. So assign edi to esi
/* for now only handle the symmetrical case */
// it's two banks, assume however that they're the same size.
// it's stupid to have any other kind, right?
movl %edi, %esi
20:
/* Compute the end address for the DRB register */
// If it is >= 8, i.e. >= 2^8 or 256, skip it.
// >= 8 is a bogus value.
cmpl $8, %edi
jae 21f
movl $1, %eax
movl %edi, %ecx
shll %cl, %eax
// increment row-end by the size of this DIMM half
addl %eax, %ebp
21:
/* Write the comuputed value for the first half of the DIMM */
movl %ebp, %edx /* value to write into %edx */
movl %ebx, %eax
shrl $16, %eax /* port address into %eax */
PCI_WRITE_CONFIG_BYTE
/* Compute the end address for the DRB register */
cmpl $8, %esi
jae 30f
mov $1, %eax
movl %esi, %ecx
shll %cl, %eax
addl %eax, %ebp
30:
/* Write the comuputed value for the second half of the DIMM */
movl %ebp, %edx /* value to write into %edx */
movl %ebx, %eax
shrl $16, %eax /* port address into %eax */
addl $1, %eax /* The second half uses one port high */
PCI_WRITE_CONFIG_BYTE
addl $0x00020001, %ebx /* increment the smbus device & the config port */
cmpb $LAST_SMBUS_MEM_DEVICE, %bl /* see if I have reached the end */
jbe spd_set_drb_loop_top
/* o.k. I'm done return now */
RET_LABEL(spd_set_drb)
/*
* Routine: spd_set_dramc
* Arguments: None
*
* Trashed: %eax, %ebx, %edx, %esp, %eflags
* Effects: Uses serial presence detect to set the
* DRAMC register, which records if ram is registerd or not,
* and controls the refresh rate.
* The refresh rate is not set here, as memory refresh
* cannot be enbaled until after memory is initialized.
* see spd_enable_refresh.
* Notes:
* FIXME: Check for illegal/unsupported ram configurations and abort
* FIXME: won't work with non-contiguous DRAM size regs (like VIA)
* need an indirect pointer to an array of reg #s
*/
spd_set_dramc:
/* auto detect if ram is registered or not. */
/* The DRAMC register also contorls the refresh rate but we can't
* set that here because we must leave refresh disabled.
* see: spd_enable_refresh
*/
/* Find the first dimm and assume the rest are the same */
/* Load the smbus device and port int %ebx */
movl $((21 << 8) | SMBUS_MEM_DEVICE_0), %ebx
1: CALLSP(smbus_read_byte)
jz 2f
andl $0x12, %eax
jmp spd_set_dramc_out
2: addl $1, %ebx /* increment the device */
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
jbe 1b
/* We couldn't find anything we must have no memory */
jmp no_memory
spd_set_dramc_out:
testb $0x12, %al
jz 2f
movl REGISTERED_DRAM, %eax
jmp 1f
2: movl NONREGISTERED_DRAM, %eax
1: movl %eax, %edx
movl REGISTERED_DRAM_REGISTER, %eax
PCI_WRITE_CONFIG_BYTE
RET_LABEL(spd_set_dramc)
/*
* Routine: spd_read_refresh
* Arguments: None
*
* Trashed: %eax, %ebx, %ecx, %edx, %esp, %eflags
* Effects: Uses serial presence detect to find refresh rates.
* returns the rate in %eax
* It's up to you to set hardware up.
* FIXME: Check for illegal/unsupported ram configurations and abort
*/
spd_read_refresh:
/* Find the first dimm and assume the rest are the same */
/* Load the smbus device and port int %ebx */
movl $((12 << 8) | SMBUS_MEM_DEVICE_0), %ebx
1: CALLSP(smbus_read_byte)
jz 2f
andl $0x7f, %eax
jmp spd_enable_refresh_out
2: addl $1, %ebx /* increment the device */
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
jbe 1b
/* We couldn't find anything we must have no memory */
xorl %eax, %eax
spd_enable_refresh_out:
RET_LABEL(spd_enable_refresh)
/*
* Routine: spd_set_rps
* Arguments: None
*
* Trashed: %eax, %ebx, %ecx, %edx, %esi, %edi, %esp, %eflags
* Effects: Uses serial presence detect to set the row size
* on a given DIMM
* Notes: %esi accumulates the row sizes of all of the DIMMs
* %ecx holds the current bit into into %esi
* %bl holds the current SMBUS device
* FIXME: Check for illegal/unsupported ram configurations and abort
*/
spd_set_rps:
/* The RPS register holds the size of a ``page'' of DRAM on each DIMM */
/* default all page sizes to 2KB */
xorl %esi, %esi
/* Index into %esi of bit to set */
movl $0 , %ecx
/* Load the smbus device into %ebx */
movl $SMBUS_MEM_DEVICE_0, %ebx
1: movb $3, %bh
CALLSP(smbus_read_byte) /* row address bits */
jz 2f
andl $0xf, %eax
movl %eax, %edi
/* I now have the row page size as a power of 2 */
subl $11, %edi /* Now make it in multiples of 2Kb */
jbe 2f
/* FIXME: do something with page sizes greather than 8KB!! */
shll %cl, %edi
orl %edi, %esi
/* side two */
movb $5, %bh
CALLSP(smbus_read_byte) /* number of physical banks */
cmp $1, %al
jbe 2f
/* for now only handle the symmtrical case */
shll $2, %edi
shll %cl, %edi
orl %edi, %esi
2: addl $1, %ebx /* increment the device */
addl $4, %ecx /* increment the shift count */
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
jbe 1b
movl $0x7f, %eax
/* I'm not sure what we should do here. Do nothing. */
/* PCI_WRITE_CONFIG_WORD*/
RET_LABEL(spd_set_rps)
/*
* Routine: spd_set_pgpol
* Arguments: None
*
* Trashed: %eax, %ebx, %ecx, %edx, %esi, %esp, %eflags
* Effects: Uses serial presence detect to set the number of banks
* on a given DIMM
* Notes: %esi accumulates the banks sizes of all of the DIMMs
* %ecx holds the current bit into into %esi
* %bl holds the current SMBUS device
* FIXME: Check for illegal/unsupported ram configurations and abort
*/
spd_set_pgpol:
/* The PGPOL register stores the number of logical banks per DIMM,
* and number of clocks the DRAM controller waits in the idle
* state.
*/
/* default all bank counts 2 */
xorl %esi, %esi
/* Index into %esi of bit to set */
movl $0 , %ecx
/* Load the smbus device into %ebx */
movl $SMBUS_MEM_DEVICE_0, %ebx
1: movb $17, %bh
CALLSP(smbus_read_byte) /* logical banks */
jz 2f
cmp $0x4, %eax
jl 2f
movl $0x1, %eax
shll %cl, %eax
orl %eax, %esi
/* side two */
movb $5, %bh
CALLSP(smbus_read_byte) /* number of physical banks */
cmp $1, %al
jbe 2f
/* for now only handle the symmtrical case */
movl $0x2, %eax
shll %cl, %eax
orl %eax, %esi
2: addl $1, %ebx /* increment the device */
addl $2, %ecx /* increment the shift count */
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
jbe 1b
shll $8, %esi
orl $0x7, %esi /* 32 clocks idle time */
movl %esi, %ecx
movl $0x78, %eax
/* I'm unclear on the concept for non-intel devices */
/* PCI_WRITE_CONFIG_WORD*/
RET_LABEL(spd_set_pgpol)
/*
* Routine: spd_enable_nbxcfg
* Arguments: None
*
* Trashed: %eax, %ebx, %ecx, %edx, %esi, %esp, %eflags
* Effects: Uses serial presence detect to set the
* ECC support flags in the NBXCFG register
* Notes: %esi accumulates the ECC support of the individual DIMMs.
* %ecx holds the bit that should be flipped for the current DIMM.
* %bl holds the smbus device that corresponds to the current DIMM.
* FIXME: Check for illegal/unsupported ram configurations and abort
*/
spd_set_nbxcfg:
/* say all dimms have no ECC support */
movl $0xFF, %esi
/* Index into %esi of bit to set */
movl $0 , %ecx
/* Load the smbus device into %ebx */
movl $SMBUS_MEM_DEVICE_0, %ebx
1: movb $11, %bh
CALLSP(smbus_read_byte) /* module error correction type */
jz 2f
cmp $0x2, %eax /* 0 == None, 1 == Parity, 2 == ECC */
jne 2f
movl $0x1, %eax
shll %cl, %eax
xorl %eax, %esi
/* side two */
movb $5, %bh
CALLSP(smbus_read_byte) /* number of physical banks */
cmp $1, %al
jbe 2f
/* The only is the symmtrical case */
movl $0x2, %eax
shll %cl, %eax
xorl %eax, %esi
2: addl $1, %ebx /* increment the device */
addl $2, %ecx /* increment the shift count */
cmpb $LAST_SMBUS_MEM_DEVICE, %bl
jbe 1b
movl %esi, %edx
/* at some point, we need to indicate how to turn ECC on. Not yet.
movl $0x53, %eax
PCI_WRITE_CONFIG_BYTE
*/
RET_LABEL(spd_set_nbxcfg)
smbus_pcibus_end:
CALL_LABEL(enable_smbus)
CALL_LABEL(setup_smbus)
smbus_end:
CALL_LABEL(smbus_setup)

View file

@ -0,0 +1,9 @@
/* Disable the TCO watch dog timer in the southbridge */
/* bridge 0, device 1f, function 0, byte d4, bit 1 */
movl $0x8000f8d4,%eax
movl $0x0cf8,%edx
outl %eax,%dx
movl $0x0cfc,%edx
movb $2,%al
outb %al,%dx

View file

@ -19,30 +19,31 @@
outb %al, $(SIO_BASE)
#define SIO_WRITE_CONFIG(value, reg) \
movb $reg, %al ; \
movb reg, %al ; \
outb %al, $(SIO_INDEX) ; \
movb $value, %al ; \
movb value, %al ; \
outb %al, $(SIO_DATA)
#define SIO_READ_CONFIG(value, reg) \
movb $reg, %al ; \
#define SIO_READ_CONFIG(reg) \
movb reg, %al ; \
outb %al, $(SIO_INDEX) ; \
inb %al, $(SIO_DATA)
inb $(SIO_DATA), %al
#define SIO_SET_LOGICAL_DEVICE(device) \
SIO_WRITE_CONFIG(device, 0x07)
SIO_WRITE_CONFIG(device, $0x07)
/* Enable pnp */
SIO_ENTER_PNP_MODE()
#if defined(SIO_SYSTEM_CLK_INPUT)
/* Setup up the clock input */
SIO_WRITE_CONFIG((0x84 | SIO_SYSTEM_CLK_INPUT), 0x24)
SIO_WRITE_CONFIG($(0x84 | SIO_SYSTEM_CLK_INPUT), $0x24)
#endif
/* enable serial 1 */
SIO_SET_LOGICAL_DEVICE(COM1_DEVICE)
SIO_WRITE_CONFIG(1, 0x30)
SIO_WRITE_CONFIG(0x3, 0x60)
SIO_WRITE_CONFIG(0xf8, 0x61)
SIO_SET_LOGICAL_DEVICE($COM1_DEVICE)
SIO_WRITE_CONFIG($1, $0x30)
SIO_WRITE_CONFIG($0x3, $0x60)
SIO_WRITE_CONFIG($0xf8, $0x61)
SIO_EXIT_PNP_MODE()

View file

@ -373,7 +373,7 @@ def nsuperio(dir, superio_commands):
superio_decls = superio_decls + decl;
superio_devices.append("&superio_" + superio_decl_name);
# note that we're using the new interface
option(dir, "USE_NEW_SUPERIO_INTERFACE")
option(dir, "USE_NEW_SUPERIO_INTERFACE=1")
numsuperio = numsuperio + 1
@ -705,6 +705,10 @@ def option(dir, option):
value = ""
if m and m.group(1):
(key, value) = m.groups()
else:
warning("Invalid option specifcation: %s assuming you meant %s=1" %
(option, option) )
value = "1"
m = option_re.match(key)
if not m:
fatal("Invalid option name: %s" % (key))

View file

@ -12,22 +12,36 @@ void print_lb_records(struct lb_record *rec, struct lb_record *last, unsigned lo
unsigned long compute_checksum(void *addr, unsigned long length)
{
unsigned short *ptr;
uint8_t *ptr;
volatile union {
uint8_t byte[2];
uint16_t word;
} value;
unsigned long sum;
unsigned long len;
/* Assumes len is a multiple of two, and addr is 2 byte aligned. */
/* compute an ip style checksum */
unsigned long i;
/* In the most straight forward way possible,
* compute an ip style checksum.
*/
sum = 0;
len = length >> 1;
ptr = addr;
while (len--) {
sum += *(ptr++);
if (sum > 0xFFFF)
sum -= 0xFFFF;
for(i = 0; i < length; i++) {
unsigned long value;
value = ptr[i];
if (i & 1) {
value <<= 8;
}
/* Add the new value */
sum += value;
/* Wrap around the carry */
if (sum > 0xFFFF) {
sum = (sum + (sum >> 16)) & 0xFFFF;
}
}
return (~sum) & 0xFFFF;
value.byte[0] = sum & 0xff;
value.byte[1] = (sum >> 8) & 0xff;
return (~value.word) & 0xFFFF;
}
#define for_each_lbrec(head, rec) \
for(rec = (struct lb_record *)(((char *)head) + sizeof(*head)); \
(((char *)rec) < (((char *)head) + sizeof(*head) + head->table_bytes)) && \
@ -157,8 +171,17 @@ void print_mainboard(struct lb_record *ptr, unsigned long addr)
rec = (struct lb_mainboard *)ptr;
max_size = rec->size - sizeof(*rec);
printf("vendor: %.*s part number: %.*s\n",
max_size - rec->vendor_idx, rec->strings + rec->vendor_idx,
max_size - rec->vendor_idx, rec->strings + rec->part_number_idx);
max_size - rec->vendor_idx, rec->strings + rec->vendor_idx,
max_size - rec->part_number_idx, rec->strings + rec->part_number_idx);
}
void print_string(struct lb_record *ptr, unsigned long addr)
{
struct lb_string *rec;
int max_size;
rec = (struct lb_string *)ptr;
max_size = rec->size - sizeof(*rec);
printf("%.*s\n", max_size, rec->string);
}
void print_option_table(struct lb_record *ptr, unsigned long addr)
@ -213,6 +236,16 @@ struct {
{ LB_TAG_MEMORY, "Memory", print_memory },
{ LB_TAG_HWRPB, "HWRPB", nop_print },
{ LB_TAG_MAINBOARD, "Mainboard", print_mainboard },
{ LB_TAG_VERSION, "Version", print_string },
{ LB_TAG_EXTRA_VERSION, "Extra Version", print_string },
{ LB_TAG_BUILD, "Build", print_string },
{ LB_TAG_COMPILE_TIME, "Compile Time", print_string },
{ LB_TAG_COMPILE_BY, "Compile By", print_string },
{ LB_TAG_COMPILE_HOST, "Compile Host", print_string },
{ LB_TAG_COMPILE_DOMAIN, "Compile Domain", print_string },
{ LB_TAG_COMPILER, "Compiler", print_string },
{ LB_TAG_LINKER, "Linker", print_string },
{ LB_TAG_ASSEMBLER, "Assembler", print_string },
{ LB_TAG_CMOS_OPTION_TABLE, "CMOS option table", print_option_table },
{ LB_TAG_OPTION, "Option", print_option },
{ LB_TAG_OPTION_ENUM, "Option Enumeration", print_option_enumeration },

5
util/mkelfImage/News Normal file
View file

@ -0,0 +1,5 @@
1.14
- Use much less complex ld magic
- Fix a small bug in the LinuxBIOS checksum verification code