diff options
author | Michael Brown | 2013-09-27 19:45:22 +0200 |
---|---|---|
committer | Michael Brown | 2014-04-08 00:39:05 +0200 |
commit | 541d4c97110cefeda23461c691e02dd2e431e609 (patch) | |
tree | a26b9d72e52dd9430f2824e3c74d1adacadd7310 | |
parent | [import] Import version 4.20 (diff) | |
download | memtest86-541d4c97110cefeda23461c691e02dd2e431e609.tar.gz memtest86-541d4c97110cefeda23461c691e02dd2e431e609.tar.xz memtest86-541d4c97110cefeda23461c691e02dd2e431e609.zip |
[import] Import version 5.01
http://www.memtest.org/download/5.01/memtest86+-5.01.tar.gz
-rw-r--r-- | Makefile | 33 | ||||
-rw-r--r-- | README | 1405 | ||||
-rw-r--r-- | README.background | 156 | ||||
-rw-r--r-- | README.build-process | 78 | ||||
-rw-r--r-- | build-number.txt | 1 | ||||
-rw-r--r-- | build.number | 1 | ||||
-rw-r--r-- | build_number.h | 9 | ||||
-rw-r--r-- | buildnumber.mak | 10 | ||||
-rw-r--r-- | changelog | 32 | ||||
-rw-r--r-- | config.c | 360 | ||||
-rw-r--r-- | config.h | 32 | ||||
-rw-r--r-- | controller.c | 2531 | ||||
-rw-r--r-- | controller.h | 15 | ||||
-rw-r--r-- | cpuid.c | 321 | ||||
-rw-r--r-- | cpuid.h | 231 | ||||
-rw-r--r-- | defs.h | 11 | ||||
-rw-r--r-- | dmi.c | 125 | ||||
-rw-r--r-- | dmi.h | 1 | ||||
-rw-r--r-- | elf.h | 43 | ||||
-rw-r--r-- | error.c | 322 | ||||
-rw-r--r-- | extra.c | 31 | ||||
-rw-r--r-- | head.S | 365 | ||||
-rw-r--r-- | init.c | 1933 | ||||
-rw-r--r-- | io.h | 1 | ||||
-rw-r--r-- | jedec_id.h | 1849 | ||||
-rw-r--r-- | lib.c | 518 | ||||
-rw-r--r-- | main.c | 1488 | ||||
-rw-r--r-- | major_version | 1 | ||||
-rwxr-xr-x | make_buildnum.sh | 20 | ||||
-rwxr-xr-x | makeiso.sh | 8 | ||||
-rw-r--r-- | memsize.c | 197 | ||||
-rw-r--r-- | memtest.bin.lds | 30 | ||||
-rw-r--r-- | memtest.lds | 22 | ||||
-rw-r--r-- | memtest_shared.lds | 106 | ||||
-rw-r--r-- | msr.h | 23 | ||||
-rw-r--r-- | mt86+_loader | bin | 784 -> 784 bytes | |||
-rw-r--r-- | mt86+_loader.asm | 4 | ||||
-rw-r--r-- | patn.c | 2 | ||||
-rw-r--r-- | pci.c | 58 | ||||
-rw-r--r-- | pci.h | 1 | ||||
-rwxr-xr-x | precomp.bin | bin | 164504 -> 150024 bytes | |||
-rw-r--r-- | random.c | 43 | ||||
-rw-r--r-- | reloc.c | 31 | ||||
-rw-r--r-- | screen_buffer.c | 83 | ||||
-rw-r--r-- | screen_buffer.h | 5 | ||||
-rw-r--r-- | setup.S | 301 | ||||
-rw-r--r-- | smp.c | 620 | ||||
-rw-r--r-- | smp.h | 159 | ||||
-rw-r--r-- | spd.c | 193 | ||||
-rw-r--r-- | spd.h | 8 | ||||
-rw-r--r-- | stddef.h | 8 | ||||
-rw-r--r-- | stdin.h | 52 | ||||
-rw-r--r-- | test.c | 1301 | ||||
-rw-r--r-- | test.h | 231 | ||||
-rw-r--r-- | version.number | 1 | ||||
-rw-r--r-- | vmem.c | 154 |
56 files changed, 8734 insertions, 6830 deletions
@@ -3,6 +3,7 @@ # Author: Chris Brady # Created: January 1, 1996 + # # Path for the floppy disk device # @@ -11,20 +12,23 @@ FDISK=/dev/fd0 AS=as -32 CC=gcc -CFLAGS= -Wall -march=i486 -m32 -O2 -fomit-frame-pointer -fno-builtin -ffreestanding -fPIC -fno-stack-protector - +CFLAGS= -Wall -march=i486 -m32 -O1 -fomit-frame-pointer -fno-builtin \ + -ffreestanding -fPIC $(SMP_FL) -fno-stack-protector + OBJS= head.o reloc.o main.o test.o init.o lib.o patn.o screen_buffer.o \ - config.o linuxbios.o memsize.o pci.o controller.o random.o spd.o \ - error.o dmi.o cpuid.o + config.o cpuid.o linuxbios.o pci.o memsize.o spd.o error.o dmi.o controller.o \ + smp.o vmem.o random.o + -all: memtest.bin memtest +all: clean memtest.bin memtest + scp memtest.bin root@192.168.0.12:/srv/tftp/mt86plus # Link it statically once so I know I don't have undefined # symbols and then link it dynamically so I have full # relocation information memtest_shared: $(OBJS) memtest_shared.lds Makefile $(LD) --warn-constructors --warn-common -static -T memtest_shared.lds \ - -o $@ $(OBJS) && \ + -o $@ $(OBJS) && \ $(LD) -shared -Bsymbolic -T memtest_shared.lds -o $@ $(OBJS) memtest_shared.bin: memtest_shared @@ -50,18 +54,22 @@ reloc.o: reloc.c $(CC) -c $(CFLAGS) -fno-strict-aliasing reloc.c test.o: test.c - $(CC) -c -Wall -march=i486 -m32 -Os -fomit-frame-pointer -fno-builtin -ffreestanding test.c + $(CC) -c -Wall -march=i486 -m32 -O0 -fomit-frame-pointer -fno-builtin -ffreestanding test.c -clean: - rm -f *.o *.s *.iso memtest.bin memtest memtest_shared memtest_shared.bin +random.o: random.c + $(CC) -c -Wall -march=i486 -m32 -O3 -fomit-frame-pointer -fno-builtin -ffreestanding random.c + +# rule for build number generation +build_number: + sh make_buildnum.sh -asm: - @./makedos.sh +clean: + rm -f *.o *.s *.iso memtest.bin memtest memtest_shared \ + memtest_shared.bin memtest.iso iso: make all ./makeiso.sh - rm -f *.o *.s memtest.bin memtest memtest_shared memtest_shared.bin install: all dd <memtest.bin >$(FDISK) bs=8192 @@ -71,4 +79,3 @@ install-precomp: dos: all cat mt86+_loader memtest.bin > memtest.exe - @@ -1,480 +1,925 @@ -Memtest86++ v4.20
-====================
-
-Table of Contents
-=================
- 1) Introduction
- 2) Licensing
- 3) Installation
- 4) Serial Port Console
- 5) Online Commands
- 6) Memory Sizing
- 7) Error Display
- 8) Trouble-shooting Memory Errors
- 9) Execution Time
- 10) Memory Testing Philosophy
- 11) Memtest86+ Test Algorithms
- 12) Individual Test Descriptions
- 13) Problem Reporting - Contact Information
- 14) Known Problems
-
-
-
-1) Introduction
-===============
-Memtest86+ is thorough, stand alone memory test for Intel/AMD x86 architecture
-systems. BIOS based memory tests are only a quick check and often miss
-failures that are detected by Memtest86+.
-
-For updates go to the Memtest86+ web page:
-
- http://www.memtest.org
-
-
-2) Licensing
-============
-Memtest86+ is released under the terms of the Gnu Public License (GPL). Other
-than the provisions of the GPL there are no restrictions for use, private or
-commercial. See: http://www.gnu.org/licenses/gpl.html for details.
-Explicit permission for inclusion of Memtest86+ in software compilations and
-publications is hereby granted.
-
-
-3) Installation (Linux Only)
-============================
-Memtest86+ is a stand alone program and can be loaded from either a disk
-partition or from a floppy disk.
-
-To build Memtest86+:
- 1) Review the Makefile and adjust options as needed.
- 2) Type "make"
-
-This creates a file named "memtest.bin" which is a bootable image. This
-image file may be copied to a floppy disk or lilo may be used to boot this
-image from a hard disk partition.
-
-To create a Memtest86+ bootdisk
- 1) Insert a blank write enabled floppy disk.
- 2) As root, Type "make install"
-
-To boot from a disk partition via lilo
- 1) Copy the image file to a permanent location (ie. /memtest).
- 2) Add an entry in the lilo config file (usually /etc/lilo.conf) to boot
- Memtest86+. Only the image and label fields need to be specified.
- The following is a sample lilo entry for booting Memtest86+:
-
- image = /memtest
- label = memtest
-
- 3) As root, type "lilo"
-
- At the lilo prompt enter memtest to boot Memtest86+.
-
-If you encounter build problems a binary image has been included (precomp.bin).
-To create a boot-disk with this pre-built image do the following:
- 1) Insert a blank write enabled floppy disk.
- 2) Type "make install-precomp"
-
-
-4) Serial Console
-=================
-Memtest86+ can be used on PC's equipped with a serial port for the console.
-By default serial port console support is not enabled since it slows
-down testing. To enable change the SERIAL_CONSOLE_DEFAULT define in
-config.h from a zero to a one. The serial console baud rate may also
-be set in config.h with the SERIAL_BAUD_RATE define. The other serial
-port settings are no parity, 8 data bits, 1 stop bit. All of the features
-used by Memtest86+ are accessible via the serial console. However, the
-screen sometimes is garbled when the online commands are used.
-
-
-5) Online Commands
-==================
-Memtest86+ has a limited number of online commands. Online commands
-provide control over caching, test selection, address range and error
-scrolling. A help bar is displayed at the bottom of the screen listing
-the available on-line commands.
-
- Command Description
-
- ESC Exits the test and does a warm restart via the BIOS.
-
- c Enters test configuration menu
- Menu options are:
- 1) Cache mode
- 2) Test selection
- 3) Address Range
- 4) Memory Sizing
- 5) Error Summary
- 6) Error Report Mode
- 7) ECC Mode
- 8) Restart
- 9) Adv. Options
-
- SP Set scroll lock (Stops scrolling of error messages)
- Note: Testing is stalled when the scroll lock is
- set and the scroll region is full.
-
- CR Clear scroll lock (Enables error message scrolling)
-
-
-6) Memory Sizing
-================
-The BIOS in modern PC's will often reserve several sections of memory for
-it's use and also to communicate information to the operating system (ie.
-ACPI tables). It is just as important to test these reserved memory blocks
-as it is for the remainder of memory. For proper operation all of memory
-needs to function properly regardless of what the eventual use is. For
-this reason Memtest86+ has been designed to test as much memory as is
-possible.
-
-However, safely and reliably detecting all of the available memory has been
-problematic. Versions of Memtest86+ prior to v0.91 would probe to find where
-memory is. This works for the vast majority of motherboards but is not 100%
-reliable. Sometimes the memory size is incorrect and worse probing the wrong
-places can in some cases cause the test to hang or crash.
-
-Starting in version 0.91 alternative methods are available for determining the
-memory size. By default the test attempts to get the memory size from the
-BIOS using the "e820" method. With "e820" the BIOS provides a table of memory
-segments and identifies what they will be used for. By default Memtest86+
-will test all of the ram marked as available and also the area reserved for
-the ACPI tables. This is safe since the test does not use the ACPI tables
-and the "e820" specifications state that this memory may be reused after the
-tables have been copied. Although this is a safe default some memory will
-not be tested.
-
-Two additional options are available through online configuration options.
-The first option (BIOS-All) also uses the "e820" method to obtain a memory
-map. However, when this option is selected all of the reserved memory
-segments are tested, regardless of what their intended use is. The only
-exception is memory segments that begin above 3gb. Testing has shown that
-these segments are typically not safe to test. The BIOS-All option is more
-thorough but could be unstable with some motherboards.
-
-The second option for memory sizing is the traditional "Probe" method.
-This is a very thorough but not entirely safe method. In the majority of
-cases the BIOS-All and Probe methods will return the same memory map.
-
-For older BIOS's that do not support the "e820" method there are two
-additional methods (e801 and e88) for getting the memory size from the
-BIOS. These methods only provide the amount of extended memory that is
-available, not a memory table. When the e801 and e88 methods are used
-the BIOS-All option will not be available.
-
-The MemMap field on the display shows what memory size method is in use.
-Also the RsvdMem field shows how much memory is reserved and is not being
-tested.
-
-
-7) Error Information
-======================
-Memtest has two options for reporting errors. The default is to report
-individual errors. In BadRAM Patterns mode patterns are created for
-use with the Linux BadRAM feature. This slick feature allows Linux to
-avoid bad memory pages. Details about the BadRAM feature can be found at:
-
- http://home.zonnet.nl/vanrein/badram
-
-For individual errors the following information is displayed when a memory
-error is detected. An error message is only displayed for errors with a
-different address or failing bit pattern. All displayed values are in
-hexadecimal.
-
- Tst: Test number
- Failing Address : Failing memory address
- Good: Expected data pattern
- Bad: Failing data pattern
- Err-Bits: Exclusive or of good and bad data (this shows the
- position of the failing bit(s))
- Count: Number of consecutive errors with the same address
- and failing bits
-
-In BadRAM Patterns mode, Lines are printed in a form badram=F1,M1,F2,M2.
-In each F/M pair, the F represents a fault address, and the corresponding M
-is a bitmask for that address. These patterns state that faults have
-occurred in addresses that equal F on all "1" bits in M. Such a pattern may
-capture more errors that actually exist, but at least all the errors are
-captured. These patterns have been designed to capture regular patterns of
-errors caused by the hardware structure in a terse syntax.
-
-The BadRAM patterns are `grown' increment-ally rather than `designed' from an
-overview of all errors. The number of pairs is constrained to five for a
-number of practical reasons. As a result, handcrafting patterns from the
-output in address printing mode may, in exceptional cases, yield better
-results.
-
-
-8) Trouble-shooting Memory Errors
-================================
-Please be aware that not all errors reported by Memtest86+ are due to
-bad memory. The test implicitly tests the CPU, L1 and L2 caches as well as
-the motherboard. It is impossible for the test to determine what causes
-the failure to occur. Most failures will be due to a problem with memory.
-When it is not, the only option is to replace parts until the failure is
-corrected.
-
-Once a memory error has been detected, determining the failing
-module is not a clear cut procedure. With the large number of motherboard
-vendors and possible combinations of simm slots it would be difficult if
-not impossible to assemble complete information about how a particular
-error would map to a failing memory module. However, there are steps
-that may be taken to determine the failing module. Here are three
-techniques that you may wish to use:
-
-1) Removing modules
-This is simplest method for isolating a failing modules, but may only be
-employed when one or more modules can be removed from the system. By
-selectively removing modules from the system and then running the test
-you will be able to find the bad module(s). Be sure to note exactly which
-modules are in the system when the test passes and when the test fails.
-
-2) Rotating modules
-When none of the modules can be removed then you may wish to rotate modules
-to find the failing one. This technique can only be used if there are
-three or more modules in the system. Change the location of two modules
-at a time. For example put the module from slot 1 into slot 2 and put
-the module from slot 2 in slot 1. Run the test and if either the failing
-bit or address changes then you know that the failing module is one of the
-ones just moved. By using several combinations of module movement you
-should be able to determine which module is failing.
-
-3) Replacing modules
-If you are unable to use either of the previous techniques then you are
-left to selective replacement of modules to find the failure.
-
-4) Avoiding allocation
-The printing mode for BadRAM patterns is intended to construct boot time
-parameters for a Linux kernel that is compiled with BadRAM support. This
-work-around makes it possible for Linux to reliably run on defective
-RAM. For more information on BadRAM support
-for Linux, sail to
-
- http://home.zonnet.nl/vanrein/badram
-
-Sometimes memory errors show up due to component incompatibility. A memory
-module may work fine in one system and not in another. This is not
-uncommon and is a source of confusion. The components are not necessarily
-bad but certain combinations may need to be avoided.
-
-I am often asked about the reliability of errors reported by Memtest86+.
-In the vast majority of cases errors reported by the test are valid.
-There are some systems that cause Memtest86+ to be confused about the size of
-memory and it will try to test non-existent memory. This will cause a large
-number of consecutive addresses to be reported as bad and generally there
-will be many bits in error. If you have a relatively small number of
-failing addresses and only one or two bits in error you can be certain
-that the errors are valid. Also intermittent errors are always valid.
-
-All valid memory errors should be corrected. It is possible that a
-particular error will never show up in normal operation. However, operating
-with marginal memory is risky and can result in data loss and even
-disk corruption. You can be sure that Murphy will get you if you know
-about a memory error and ignore it.
-
-Memtest86+ can not diagnose many types of PC failures. For example a
-faulty CPU that causes Windows to crash will most likely just cause
-Memtest86+ to crash in the same way.
-
-
-9) Execution Time
-==================
-The time required for a complete pass of Memtest86+ will vary greatly
-depending on CPU speed, memory speed and memory size. Memtest86+ executes
-indefinitely. The pass counter increments each time that all of the
-selected tests have been run. Generally a single pass is sufficient to
-catch all but the most obscure errors. However, for complete confidence
-when intermittent errors are suspected testing for a longer period is advised.
-
-10) Memory Testing Philosophy
-=============================
-There are many good approaches for testing memory. However, many tests
-simply throw some patterns at memory without much thought or knowledge
-of memory architecture or how errors can best be detected. This
-works fine for hard memory failures but does little to find intermittent
-errors. BIOS based memory tests are useless for finding intermittent
-memory errors.
-
-Memory chips consist of a large array of tightly packed memory cells,
-one for each bit of data. The vast majority of the intermittent failures
-are a result of interaction between these memory cells. Often writing a
-memory cell can cause one of the adjacent cells to be written with the
-same data. An effective memory test attempts to test for this
-condition. Therefore, an ideal strategy for testing memory would be
-the following:
-
- 1) write a cell with a zero
- 2) write all of the adjacent cells with a one, one or more times
- 3) check that the first cell still has a zero
-
-It should be obvious that this strategy requires an exact knowledge
-of how the memory cells are laid out on the chip. In addition there is a
-never ending number of possible chip layouts for different chip types
-and manufacturers making this strategy impractical. However, there
-are testing algorithms that can approximate this ideal strategy.
-
-
-11) Memtest86+ Test Algorithms
-=============================
-Memtest86+ uses two algorithms that provide a reasonable approximation
-of the ideal test strategy above. The first of these strategies is called
-moving inversions. The moving inversion test works as follows:
-
- 1) Fill memory with a pattern
- 2) Starting at the lowest address
- 2a check that the pattern has not changed
- 2b write the patterns complement
- 2c increment the address
- repeat 2a - 2c
- 3) Starting at the highest address
- 3a check that the pattern has not changed
- 3b write the patterns complement
- 3c decrement the address
- repeat 3a - 3c
-
-This algorithm is a good approximation of an ideal memory test but
-there are some limitations. Most high density chips today store data
-4 to 16 bits wide. With chips that are more than one bit wide it
-is impossible to selectively read or write just one bit. This means
-that we cannot guarantee that all adjacent cells have been tested
-for interaction. In this case the best we can do is to use some
-patterns to insure that all adjacent cells have at least been written
-with all possible one and zero combinations.
-
-It can also be seen that caching, buffering and out of order execution
-will interfere with the moving inversions algorithm and make less effective.
-It is possible to turn off cache but the memory buffering in new high
-performance chips can not be disabled. To address this limitation a new
-algorithm I call Modulo-X was created. This algorithm is not affected by
-cache or buffering. The algorithm works as follows:
- 1) For starting offsets of 0 - 20 do
- 1a write every 20th location with a pattern
- 1b write all other locations with the patterns complement
- repeat 1b one or more times
- 1c check every 20th location for the pattern
-
-This algorithm accomplishes nearly the same level of adjacency testing
-as moving inversions but is not affected by caching or buffering. Since
-separate write passes (1a, 1b) and the read pass (1c) are done for all of
-memory we can be assured that all of the buffers and cache have been
-flushed between passes. The selection of 20 as the stride size was somewhat
-arbitrary. Larger strides may be more effective but would take longer to
-execute. The choice of 20 seemed to be a reasonable compromise between
-speed and thoroughness.
-
-
-12) Individual Test Descriptions
-================================
-Memtest86+ executes a series of numbered test sections to check for
-errors. These test sections consist of a combination of test
-algorithm, data pattern and caching. The execution order for these tests
-were arranged so that errors will be detected as rapidly as possible.
-A description of each of the test sections follows:
-
-Test 0 [Address test, walking ones, no cache]
- Tests all address bits in all memory banks by using a walking ones
- address pattern. Errors from this test are not used to calculate
- BadRAM patterns.
-
-Test 1 [Address test, own address]
- Each address is written with its own address and then is checked
- for consistency. In theory previous tests should have caught any
- memory addressing problems. This test should catch any addressing
- errors that somehow were not previously detected.
-
-Test 2 [Moving inversions, ones&zeros]
- This test uses the moving inversions algorithm with patterns of all
- ones and zeros. Cache is enabled even though it interferes to some
- degree with the test algorithm. With cache enabled this test does not
- take long and should quickly find all "hard" errors and some more
- subtle errors. This section is only a quick check.
-
-Test 3 [Moving inversions, 8 bit pat]
- This is the same as test 1 but uses a 8 bit wide pattern of
- "walking" ones and zeros. This test will better detect subtle errors
- in "wide" memory chips. A total of 20 data patterns are used.
-
-Test 4 [Moving inversions, random pattern]
- Test 4 uses the same algorithm as test 1 but the data pattern is a
- random number and it's complement. This test is particularly effective
- in finding difficult to detect data sensitive errors. A total of 60
- patterns are used. The random number sequence is different with each pass
- so multiple passes increase effectiveness.
-
-Test 5 [Block move, 64 moves]
- This test stresses memory by using block move (movsl) instructions
- and is based on Robert Redelmeier's burnBX test. Memory is initialized
- with shifting patterns that are inverted every 8 bytes. Then 4MB blocks
- of memory are moved around using the movsl instruction. After the moves
- are completed the data patterns are checked. Because the data is checked
- only after the memory moves are completed it is not possible to know
- where the error occurred. The addresses reported are only for where the
- bad pattern was found. Since the moves are constrained to a 8MB segment
- of memory the failing address will always be lest than 8MB away from the
- reported address. Errors from this test are not used to calculate
- BadRAM patterns.
-
-Test 6 [Moving inversions, 32 bit pat]
- This is a variation of the moving inversions algorithm that shifts the data
- pattern left one bit for each successive address. The starting bit position
- is shifted left for each pass. To use all possible data patterns 32 passes
- are required. This test is quite effective at detecting data sensitive
- errors but the execution time is long.
-
-Test 7 [Random number sequence]
- This test writes a series of random numbers into memory. By resetting the
- seed for the random number the same sequence of number can be created for
- a reference. The initial pattern is checked and then complemented and
- checked again on the next pass. However, unlike the moving inversions test
- writing and checking can only be done in the forward direction.
-
-Test 8 [Modulo 20, ones&zeros]
- Using the Modulo-X algorithm should uncover errors that are not
- detected by moving inversions due to cache and buffering interference
- with the the algorithm. All ones and zeros are used for data patterns.
-
-Test 9 [Bit fade test, 90 min, 2 patterns]
- The bit fade test initializes all of memory with a pattern and then
- sleeps for 90 minutes. Then memory is examined to see if any memory bits
- have changed. All ones and all zero patterns are used. This test takes
- 3 hours to complete. The Bit Fade test is not included in the normal test
- sequence and must be run manually via the runtime configuration menu.
-
-
-14) Known Problems
-==================
-Sometimes when booting from a floppy disk the following messages scroll up
-on the screen:
- X:8000
- AX:0212
- BX:8600
- CX:0201
- DX:0000
-This the BIOS reporting floppy disk read errors. Either re-write or toss
-the floppy disk.
-
-Memtest86+ has no support for multiple CPUs. Memtest86+ should run
-without problems, but it will only use one CPU.
-
-Memtest86+ can not diagnose many types of PC failures. For example a
-faulty CPU that causes Windows to crash will most likely just cause
-Memtest86+ to crash in the same way.
-
-There have been numerous reports of errors in only tests 5 and 8 on Athlon
-systems. Often the memory works in a different system or the vendor insists
-that it is good. In these cases the memory is not necessarily bad but is
-not able to operate reliably at Athlon speeds. Sometimes more conservative
-memory timings on the motherboard will correct these errors. In other
-cases the only option is to replace the memory with better quality, higher
-speed memory. Don't buy cheap memory and expect it to work with an Athlon!
-
-Memtest86+ supports all types of memory. If fact the test has absolutely
-no knowledge of the memory type nor does it need to. This not a problem
-or bug but is listed here due to the many questions I get about this issue.
-
-Changes in the compiler and loader have caused problems with
-Memtest86+ resulting in both build failures and errors in execution. A
-binary image (precomp.bin) of the test is included and may be used if
-problems are encountered.
-
-
+ ==================== + = MemTest-86 v4.0 = + = 28 Mar, 2011 = + = Chris Brady = + ==================== +Table of Contents +================= + 1) Introduction + 2) Licensing + 3) Installation + 4) Serial Port Console + 5) Online Commands + 6) Memory Sizing + 7) Error Display + 8) Trouble-shooting Memory Errors + 9) Execution Time + 10) Memory Testing Philosophy + 11) Memtest86 Test Algorithms + 12) Individual Test Descriptions + 13) Problem Reporting - Contact Information + 14) Known Problems + 15) Planned Features List + 16) Change Log + 17) Acknowledgments + + +1) Introduction +=============== +Memtest86 is thorough, stand alone memory test for Intel/AMD x86 architecture +systems. BIOS based memory tests are only a quick check and often miss +failures that are detected by Memtest86. + +For updates go to the Memtest86 web page: + + http://www.memtest86.com + + +2) Licensing +============ +Memtest86 is released under the terms of the Gnu Public License (GPL). Other +than the provisions of the GPL there are no restrictions for use, private or +commercial. See: http://www.gnu.org/licenses/gpl.html for details. + + +3) Linux Installation +============================ +Memtest86 is a stand alone program and can be loaded from either a disk +partition or from a floppy disk. + +To build Memtest86: + 1) Review the Makefile and adjust options as needed. + 2) Type "make" + +This creates a file named "memtest.bin" which is a bootable image. This +image file may be copied to a floppy disk or may be loaded from a disk +partition via Lilo or Grub image from a hard disk partition. + + To create a Memtest86 bootdisk + 1) Insert a blank write enabled floppy disk. + 2) As root, Type "make install" + + To boot from a disk partition via Grub + 1) Copy the image file to a permanent location (ie. /boot/memtest.bin). + 2) Add an entry in the Grub config file (/boot/grub/menu.lst) to boot + memtest86. Only the title and kernel fields need to be specified. + The following is a sample Grub entry for booting memtest86: + + title Memtest86 + kernel (hd0,0)/memtest.bin + + To boot from a disk partition via Lilo + 1) Copy the image file to a permanent location (ie. /boot/memtest.bin). + 2) Add an entry in the lilo config file (usually /etc/lilo.conf) to boot + memtest86. Only the image and label fields need to be specified. + The following is a sample Lilo entry for booting memtest86: + + image = /boot/memtest.bin + label = memtest86 + + 3) As root, type "lilo" + +If you encounter build problems a binary image has been included (precomp.bin). +To create a boot-disk with this pre-built image do the following: + 1) Insert a blank write enabled floppy disk. + 2) Type "make install-precomp" + + +4) Serial Console +================= +Memtest86 can be used on PC's equipped with a serial port for the console. +By default serial port console support is not enabled since it slows +down testing. To enable change the SERIAL_CONSOLE_DEFAULT define in +config.h from a zero to a one. The serial console baud rate may also +be set in config.h with the SERIAL_BAUD_RATE define. The other serial +port settings are no parity, 8 data bits, 1 stop bit. All of the features +used by memtest86 are accessible via the serial console. However, the +screen sometimes is garbled when the online commands are used. + + +5) Online Commands +================== +Memtest86 has a limited number of online commands. Online commands +provide control over caching, test selection, address range and error +scrolling. A help bar is displayed at the bottom of the screen listing +the available on-line commands. + + Command Description + + ESC Exits the test and does a warm restart via the BIOS. + + c Enters test configuration menu + Menu options are: + 1) Test selection + 2) Address Range + 3) Error Report Mode + 4) CPU Selection Mode + 5) Refresh Screen + + SP Set scroll lock (Stops scrolling of error messages) + Note: Testing is stalled when the scroll lock is + set and the scroll region is full. + + CR Clear scroll lock (Enables error message scrolling) + + +6) Error Information +====================== +Memtest has three options for reporting errors. The default is an an error +summary that displays the most relevant error information. The second option +is reporting of individual errors. In BadRAM Patterns mode patterns are +created for use with the Linux BadRAM feature. This slick feature allows +Linux to avoid bad memory pages. Details about the BadRAM feature can be +found at: + + http://home.zonnet.nl/vanrein/badram + +The error summary mode displays the following information: + + Error Confidence Value: + A value that indicates the validity of the errors being reported with + larger values indicating greater validity. There is a high probability + that all errors reported are valid regardless of this value. However, + when this value exceeds 100 it is nearly impossible that the reported + errors will be invalid. + + Lowest Error Address: + The lowest address that where an error has been reported. + + Highest Error Address: + The highest address that where an error has been reported. + + Bits in Error Mask: + A mask of all bits that have been in error (hexadecimal). + + Bits in Error: + Total bit in error for all error instances and the min, max and average + bit in error of each individual occurrence. + + Max Contiguous Errors: + The maximum of contiguous addresses with errors. + + ECC Correctable Errors: + The number of errors that have been corrected by ECC hardware. + + Test Errors: + On the right hand side of the screen the number of errors for each test + are displayed. + +For individual errors the following information is displayed when a memory +error is detected. An error message is only displayed for errors with a +different address or failing bit pattern. All displayed values are in +hexadecimal. + + Tst: Test number + Failing Address: Failing memory address + Good: Expected data pattern + Bad: Failing data pattern + Err-Bits: Exclusive or of good and bad data (this shows the + position of the failing bit(s)) + Count: Number of consecutive errors with the same address + and failing bits + CPU: CPU that detected the error + +In BadRAM Patterns mode, Lines are printed in a form badram=F1,M1,F2,M2. +In each F/M pair, the F represents a fault address, and the corresponding M +is a bitmask for that address. These patterns state that faults have +occurred in addresses that equal F on all "1" bits in M. Such a pattern may +capture more errors that actually exist, but at least all the errors are +captured. These patterns have been designed to capture regular patterns of +errors caused by the hardware structure in a terse syntax. + +The BadRAM patterns are `grown' increment-ally rather than `designed' from an +overview of all errors. The number of pairs is constrained to five for a +number of practical reasons. As a result, handcrafting patterns from the +output in address printing mode may, in exceptional cases, yield better +results. + + +7) Trouble-shooting Memory Errors +================================ +Please be aware that not all errors reported by Memtest86 are due to +bad memory. The test implicitly tests the CPU, L1 and L2 caches as well as +the motherboard. It is impossible for the test to determine what causes +the failure to occur. Most failures will be due to a problem with memory. +When it is not, the only option is to replace parts until the failure is +corrected. + +Once a memory error has been detected, determining the failing +module is not a clear cut procedure. With the large number of motherboard +vendors and possible combinations of simm slots it would be difficult if +not impossible to assemble complete information about how a particular +error would map to a failing memory module. However, there are steps +that may be taken to determine the failing module. Here are three +techniques that you may wish to use: + +1) Removing modules +This is simplest method for isolating a failing modules, but may only be +employed when one or more modules can be removed from the system. By +selectively removing modules from the system and then running the test +you will be able to find the bad module(s). Be sure to note exactly which +modules are in the system when the test passes and when the test fails. + +2) Rotating modules +When none of the modules can be removed then you may wish to rotate modules +to find the failing one. This technique can only be used if there are +three or more modules in the system. Change the location of two modules +at a time. For example put the module from slot 1 into slot 2 and put +the module from slot 2 in slot 1. Run the test and if either the failing +bit or address changes then you know that the failing module is one of the +ones just moved. By using several combinations of module movement you +should be able to determine which module is failing. + +3) Replacing modules +If you are unable to use either of the previous techniques then you are +left to selective replacement of modules to find the failure. + +4) Avoiding allocation +The printing mode for BadRAM patterns is intended to construct boot time +parameters for a Linux kernel that is compiled with BadRAM support. This +work-around makes it possible for Linux to reliably run on defective +RAM. For more information on BadRAM support +for Linux, sail to + + http://home.zonnet.nl/vanrein/badram + +Sometimes memory errors show up due to component incompatibility. A memory +module may work fine in one system and not in another. This is not +uncommon and is a source of confusion. The components are not necessarily +bad but certain combinations may need to be avoided. + +I am often asked about the reliability of errors reported by Mestest86. +In the vast majority of cases errors reported by the test are valid. +There are some systems that cause Memtest86 to be confused about the size of +memory and it will try to test non-existent memory. This will cause a large +number of consecutive addresses to be reported as bad and generally there +will be many bits in error. If you have a relatively small number of +failing addresses and only one or two bits in error you can be certain +that the errors are valid. Also intermittent errors are always valid. + +All valid memory errors should be corrected. It is possible that a +particular error will never show up in normal operation. However, operating +with marginal memory is risky and can result in data loss and even +disk corruption. You can be sure that Murphy will get you if you know +about a memory error and ignore it. + +Memtest86 can not diagnose many types of PC failures. For example a +faulty CPU that causes Windows to crash will most likely just cause +Memtest86 to crash in the same way. + + +8) Execution Time +================== +The time required for a complete pass of Memtest86 will vary greatly +depending on CPU speed, memory speed and memory size. Memtest86 executes +indefinitely. The pass counter increments each time that all of the +selected tests have been run. Generally a single pass is sufficient to +catch all but the most obscure errors. However, for complete confidence +when intermittent errors are suspected testing for a longer period is advised. + +9) Memory Testing Philosophy +============================= +There are many good approaches for testing memory. However, many tests +simply throw some patterns at memory without much thought or knowledge +of memory architecture or how errors can best be detected. This +works fine for hard memory failures but does little to find intermittent +errors. BIOS based memory tests are useless for finding intermittent +memory errors. + +Memory chips consist of a large array of tightly packed memory cells, +one for each bit of data. The vast majority of the intermittent failures +are a result of interaction between these memory cells. Often writing a +memory cell can cause one of the adjacent cells to be written with the +same data. An effective memory test attempts to test for this +condition. Therefore, an ideal strategy for testing memory would be +the following: + + 1) write a cell with a zero + 2) write all of the adjacent cells with a one, one or more times + 3) check that the first cell still has a zero + +It should be obvious that this strategy requires an exact knowledge +of how the memory cells are laid out on the chip. In addition there is a +never ending number of possible chip layouts for different chip types +and manufacturers making this strategy impractical. However, there +are testing algorithms that can approximate this ideal strategy. + + +11) Memtest86 Test Algorithms +============================= +Memtest86 uses two algorithms that provide a reasonable approximation +of the ideal test strategy above. The first of these strategies is called +moving inversions. The moving inversion test works as follows: + + 1) Fill memory with a pattern + 2) Starting at the lowest address + 2a check that the pattern has not changed + 2b write the patterns complement + 2c increment the address + repeat 2a - 2c + 3) Starting at the highest address + 3a check that the pattern has not changed + 3b write the patterns complement + 3c decrement the address + repeat 3a - 3c + +This algorithm is a good approximation of an ideal memory test but +there are some limitations. Most high density chips today store data +4 to 16 bits wide. With chips that are more than one bit wide it +is impossible to selectively read or write just one bit. This means +that we cannot guarantee that all adjacent cells have been tested +for interaction. In this case the best we can do is to use some +patterns to insure that all adjacent cells have at least been written +with all possible one and zero combinations. + +It can also be seen that caching, buffering and out of order execution +will interfere with the moving inversions algorithm and make less effective. +It is possible to turn off cache but the memory buffering in new high +performance chips can not be disabled. To address this limitation a new +algorithm I call Modulo-X was created. This algorithm is not affected by +cache or buffering. The algorithm works as follows: + 1) For starting offsets of 0 - 20 do + 1a write every 20th location with a pattern + 1b write all other locations with the patterns complement + repeat 1b one or more times + 1c check every 20th location for the pattern + +This algorithm accomplishes nearly the same level of adjacency testing +as moving inversions but is not affected by caching or buffering. Since +separate write passes (1a, 1b) and the read pass (1c) are done for all of +memory we can be assured that all of the buffers and cache have been +flushed between passes. The selection of 20 as the stride size was somewhat +arbitrary. Larger strides may be more effective but would take longer to +execute. The choice of 20 seemed to be a reasonable compromise between +speed and thoroughness. + + +11) Individual Test Descriptions +================================ +Memtest86 executes a series of numbered test sections to check for +errors. These test sections consist of a combination of test +algorithm, data pattern and caching. The execution order for these tests +were arranged so that errors will be detected as rapidly as possible. +A description of each of the test sections follows: + +Test 0 [Address test, walking ones, no cache] + Tests all address bits in all memory banks by using a walking ones + address pattern. Errors from this test are not used to calculate + BadRAM patterns. + +Test 1 [Address test, own address Sequential] + Each address is written with its own address and then is checked + for consistency. In theory previous tests should have caught any + memory addressing problems. This test should catch any addressing + errors that somehow were not previously detected. This test is done + sequentially with each available CPU. + +Test 2 [Address test, own address Parallel] + Same as test 1 but the testing is done in parallel using all CPUs using + overlapping addresses. + +Test 3 [Moving inversions, ones&zeros Sequential] + This test uses the moving inversions algorithm with patterns of all + ones and zeros. Cache is enabled even though it interferes to some + degree with the test algorithm. With cache enabled this test does not + take long and should quickly find all "hard" errors and some more + subtle errors. This test is done sequentially with each available CPU. + +Test 4 [Moving inversions, ones&zeros Parallel] + Same as test 3 but the testing is done in parallel using all CPUs. + +Test 5 [Moving inversions, 8 bit pat] + This is the same as test 4 but uses a 8 bit wide pattern of + "walking" ones and zeros. This test will better detect subtle errors + in "wide" memory chips. A total of 20 data patterns are used. + +Test 6 [Moving inversions, random pattern] + Test 6 uses the same algorithm as test 4 but the data pattern is a + random number and it's complement. This test is particularly effective + in finding difficult to detect data sensitive errors. + The random number sequence is different with each pass + so multiple passes increase effectiveness. + +Test 7 [Block move, 64 moves] + This test stresses memory by using block move (movsl) instructions + and is based on Robert Redelmeier's burnBX test. Memory is initialized + with shifting patterns that are inverted every 8 bytes. Then 4MB blocks + of memory are moved around using the movsl instruction. After the moves + are completed the data patterns are checked. Because the data is checked + only after the memory moves are completed it is not possible to know + where the error occurred. The addresses reported are only for where the + bad pattern was found. Since the moves are constrained to a 8MB segment + of memory the failing address will always be lest than 8MB away from the + reported address. Errors from this test are not used to calculate + BadRAM patterns. + +Test 8 [Moving inversions, 32 bit pat] + This is a variation of the moving inversions algorithm that shifts the data + pattern left one bit for each successive address. The starting bit position + is shifted left for each pass. To use all possible data patterns 32 passes + are required. This test is quite effective at detecting data sensitive + errors but the execution time is long. + +Test 9 [Random number sequence] + This test writes a series of random numbers into memory. By resetting the + seed for the random number the same sequence of number can be created for + a reference. The initial pattern is checked and then complemented and + checked again on the next pass. However, unlike the moving inversions test + writing and checking can only be done in the forward direction. + +Test 10 [Modulo 20, random pattern] + Using the Modulo-X algorithm should uncover errors that are not + detected by moving inversions due to cache and buffering interference + with the the algorithm. A 32 bit random pattern is used. + +Test 11 [Bit fade test, 2 patterns] + The bit fade test initializes all of memory with a pattern and then + sleeps for 5 minutes. Then memory is examined to see if any memory bits + have changed. All ones and all zero patterns are used. + + +12) Problem Reporting - Contact Information +=========================================== +Due to the growing popularity of Memtest86 (more than 200,000 downloads per +month) I have been inundated by, questions, feedback, problem reports and +requests for enhancements. I simply do not have time to respond to ANY Memtest86 +emails. Bug reports and suggestions are welcome but will typically not be +responded to. + +*** NOTE: *** The Keyword MEM86 must appear in the subject of all emails or +the message will be automaticly deleted before it gets to me. This thanks to +spam and viruses! + +Problems/Bugs: +Before submitting a problem report please check the Known Problems section +to see if this problem has already been reported. Be sure to include the +version number and also any details that may be relevant. + +Chris Brady, Email: bugs@memtest86.com + +With some PC's Memtest86 will just die with no hints as to what went wrong. +Without any details it is impossible to fix these failures. Fixing these +problems will require debugging on your part. There is no point in reporting +these failures unless you have a Linux system and would be willing to debug +the failure. + +Enhancements: +If you would like to request an enhancement please see if is already on +the Planned Features List before sending your request. All requests will +be considered, but not all can be implemented. If you are be interested in +contributing code please contact me so that the integration can be +co-ordinated. + +Chris Brady, Email: enhance@memtest86.com + +Questions: +Unfortunately, I do not have time to respond to any questions or provide +assistance with troubleshooting problems. Please read the Troubleshooting +and Known Problems sections for assistance with problems. These sections have +the answers for the questions that I have answers to. If there is not an +answer for your problem in these sections it is probably not something I can +help you with. + + +15) Known Problems +================== +Sometimes when booting from a floppy disk the following messages scroll up +on the screen: + X:8000 + AX:0212 + BX:8600 + CX:0201 + DX:0000 +This the BIOS reporting floppy disk read errors. Either re-write or toss +the floppy disk. + +Memtest86 can not diagnose many types of PC failures. For example a +faulty CPU that causes Windows to crash will most likely just cause +Memtest86 to crash in the same way. + +There have been numerous reports of errors in only the block move test. Often +the memory works in a different system or the vendor insists that it is good. +In these cases the memory is not necessarily bad but is not able to operate +reliably high speeds. Sometimes more conservative memory timings on the +motherboard will correct these errors. In other cases the only option is to +replace the memory with better quality, higher speed memory. Don't buy cheap +memory and expect it to work at full speed. + +Memtest86 supports all types of memory. If fact the test has absolutely +no knowledge of the memory type nor does it need to. This not a problem +or bug but is listed here due to the many questions I get about this issue. + +Changes in the compiler and loader have caused problems with +Memtest86 resulting in both build failures and errors in execution. A +binary image (precomp.bin) of the test is included and may be used if +problems are encountered. + + +15) Planned Features List +========================= +This is a list of enhancements planned for future releases of Memtest86. +There is no timetable for when these will be implemented. + + - Testing in 64 bit mode with 64 data patterns + - Support for reporting ECC errors was removed in the 4.0 release. A + simplified implementation of ECC reporting is planned for a future release. + + +16) Change Log +============== +Enhancements in v4.0 (28/Mar/2011) + + Full support for testing with multiple CPUs. All tests except for #11 (Bit + Fade) have been multi-threaded. A maximum of 16 CPUs will be used for testing. + + CPU detection has been completely re-written to use the brand ID string + rather than the cumbersome, difficult to maintain and often out of date + CPUID family information. All new processors will now be correctly + identified without requiring code support. + + All code related to controller identification, PCI and DMI has been removed. + This may be a controversial decision and was not made lightly. The following + are justifications for the decision: + + 1. Controller identification has nothing to do with actual testing of + memory, the core purpose of Memtest86. + 2. This code needed to be updated with every new chipset. With the ever + growing number of chipsets it is not possible to keep up with the + changes. The result is that new chipsets were more often than not + reported in-correctly. In the authors opinion incorrect information is + worse than no information. + 3. Probing for chipset information carries the risk of making the program + crash. + 4. The amount of code involved with controller identification was quite + large, making support more difficult. + + Removing this code also had the unfortunate effect of removing reporting of + correctable ECC errors. The code to support ECC was hopelessly intertwined + the controller identification code. A fresh, streamlined implementation of + ECC reporting is planned for a future release. + + A surprising number of conditions existed that potentially cause problems + when testing more than 4 GB of memory. Most if not all of these conditions + have been identified and corrected. + + A number of cases were corrected where not all of memory was being tested. + For most tests the last word of each test block was not tested. In addition + an error in the paging code was fixed that omitted from testing the last 256 + bytes of each block above 2 GB. + + The information display has been simplified and a number of details that were + not relevant to testing were removed. + + Memory speed reporting has been parallelized for more accurate reporting for + multi channel memory controllers. + + This is a major re-write of the Memtest86 with a large number of minor + bug-fixes and substantial cleanup and re-organization of the code. + + +Enhancements in v3.5 (3/Jan/2008) + + Limited support for execution with multiple CPUs. CPUs are selected + round-robin or sequential for each test. + + Support for additional chipsets. (from Memtest86+ v2.11). + + Additions and corrections for CPU detection including reporting of L3 cache. + + Reworked information display for better readability and new information. + + Abbreviated iterations for first pass. + + Enhancements to memory sizing. + + Misc fixes. + +Enhancements in v3.4 (2/Aug/2007) + + A new error summary display with error confidence analysis. + + Support for additional chipsets. (from Memtest86+ v1.70). + + Additions and corrections for CPU detection. + + Support for memory module information reporting. + + Misc bug fixes. + +Enhancements in v3.3 (12/Jan/2007) + + Added support for additional chipsets. (from Memtest86+ v1.60) + + Changed Modulo 20 test (#8) to use a more effective random pattern rather + than simple ones and zeros. + + Fixed a bug that prevented testing of low memory. + + Added an advanced menu option to display SPD info (only for selected + chipsets). + + Updated CPU detection for new CPUs and corrected some bugs. + + Reworked online command text for better clarity. + + Added a fix to correct a Badram pattern bug. + + +Enhancements in v3.2 (11/Nov/2004) + + Added two new, highly effective tests that use random number patterns + (tests 4 and 6). + + Reworked the online commands: + - Changed wording for better clarity + - Dropped Cache Mode menu + + Updated CPU detection for newer AMD, Intel and Cyrix CPUs. + + Reworked test sequence: + - Dropped ineffective non cached tests (Numbers 7-11) + - Changed cache mode to "cached" for test 2 + - Fixed bug that did not allow some tests to be skipped + - Added bailout for Bit fade test + + Error reports are highlighted in red to provide a more vivid error + indication. + + Added support for a large number of additional chipsets. (from Memtest86+ + v1.30) + + Added an advanced setup feature that with new chiset allows memory timings + to be altered from inside Memtest86. (from Memtest86+ v1.30) + + +Enhancements in v3.1 (11/Mar/2004) + + Added processor detection for newer AMD processors. + + Added new "Bit Fade" extended test. + + Fixed a compile time bug with gcc version 3.x. + + E7500 memory controller ECC support + + Added support for 16bit ECC syndromes + + Option to keep the serial port baud rate of the boot loader + + +Enhancements in v3.0 (22/May/2002) Provided by Eric Biederman + + Testing of more than 2gb of memory is at last fixed (tested with 6Gb) + + The infrastructure is to poll ecc error reporting chipset regisets, + and the support has been done for some chipsets. + + Uses dynamic relocation information records to make itself PIC + instead of requiring 2 copies of memtest86 in the binary. + + The serial console code does not do redundant writes to the serial port + Very little slow down at 9600 baud. + + You can press ^l or just l to get a screen refresh, when you are + connecting and UN-connecting a serial cable. + + Net-booting is working again + + Linux-BIOS support (To get the memory size) + + Many bug-fixes and code cleanup. + +Enhancements in v2.9 (29/Feb/2002) + + The memory sizing code has been completely rewritten. By default + Memtest86 gets a memory map from the BIOS that is now used to find + available memory. A new online configuration option provides three + choices for how memory will be sized, including the old "probe" method. + The default mode generally will not test all of memory, but should be more + stable. See the "Memory Sizing" section for details. + + Testing of more than 2gb of memory should now work. A number of bugs + were found and corrected that prevented testing above 2gb. Testing + with more than 2gb has been limited and there could be problems with a + full 4gb of memory. + + Memory is divided into segments for testing. This allow for frequent + progress updates and responsiveness to interactive commands. The + memory segment size has been increased from 8 to 32mb. This should + improve testing effectiveness but progress reports will be less frequent. + + Minor bug fixes. + +Enhancements in v2.8 (18/Oct/2001) + Eric Biederman reworked the build process making it far simpler and also + to produce a network bootable ELF image. + + Re-wrote the memory and cache speed detection code. Previously the + reported numbers were inaccurate for Intel CPU's and completely wrong + for Athlon/Duron CPU's. + + By default the serial console is disabled since this was slowing + down testing. + + Added CPU detection for Pentium 4. + + +Enhancements in v2.7 (12/Jul/2001) + Expanded workaround for errors caused by BIOS USB keyboard support to + include test #5. + + Re-worked L1 / L2 cache detection code to provide clearer reporting. + + Fixed an obvious bug in the computation of cache and memory speeds. + + Changed on-line menu to stay in the menu between option selections. + + Fixed bugs in the test restart and redraw code. + + Adjusted code size to fix compilation problems with RedHat 7.1. + + Misc updates to the documentation. + +Enhancements in v2.6 (25/May/2001) + Added workaround for errors caused by BIOS USB keyboard support. + + Fixed problems with reporting of 1 GHZ + processor speeds. + + Fixed Duron cache detection. + + Added screen buffer so that menus will work correctly from a serial + console. + + The Memtest86 image is now built in ELF format. + +Enhancements in v2.5 (14/Dec/00) + Enhanced CPU and cache detection to correctly identify Duron CPU + and K6-III 1MB cache. + + Added code to report cache-able memory size. + + Added limited support for parity memory. + + Support was added to allow use of on-line commands from a serial + port. + + Dropped option for changing refresh rates. This was not useful + and did not work on newer motherboards. + + Improved fatal exception reporting to include a register and stack + dump. + + The pass number is now displayed in the error report. + + Fixed a bug that crashed the test when selecting one of the extended + tests. + +Enhancements in v2.4 + The error report format was reworked for better clarity and now + includes a decimal address in megabytes. + + A new memory move test was added (from Robert Redelmeier's CPU-Burn) + + The test sequence and iterations were modified. + + Fixed scrolling problems with the BadRAM patterns. + + +Enhancements in v2.3 + A progress meter was added to replace the spinner and dots. + + Measurement and reporting of memory and cache performance + was added. + + Support for creating BadRAM patterns was added. + + All of the test routines were rewritten in assembler to + improve both test performance and speed. + + The screen layout was reworked to hopefully be more readable. + + An error summary option was added to the online commands. + + +Enhancements in v2.2 + Added two new address tests + + Added an on-line command for setting test address range + + Optimized test code for faster execution (-O3, -funroll-loops and + -fomit-frame-pointer) + + Added and elapsed time counter. + + Adjusted menu options for better consistency + + +Enhancements in v2.1 + Fixed a bug in the CPU detection that caused the test to + hang or crash with some 486 and Cryrix CPU's + + Added CPU detection for Cyrix CPU's + + Extended and improved CPU detection for Intel and AMD CPU's + + Added a compile time option (BIOS_MEMSZ) for obtaining the last + memory address from the BIOS. This should fix problems with memory + sizing on certain motherboards. This option is not enabled by default. + It may be enabled be default in a future release. + +Enhancements in v2.0 + Added new Modulo-20 test algorithm. + + Added a 32 bit shifting pattern to the moving inversions algorithm. + + Created test sections to specify algorithm, pattern and caching. + + Improved test progress indicators. + + Created popup menus for configuration. + + Added menu for test selection. + + Added CPU and cache identification. + + Added a "bail out" feature to quit the current test when it does not + fit the test selection parameters. + + Re-arranged the screen layout and colors. + + Created local include files for I/O and serial interface definitions + rather than using the sometimes incompatible system include files. + + Broke up the "C" source code into four separate source modules. + +Enhancements in v1.5 + Some additional changes were made to fix obscure memory sizing + problems. + + The 4 bit wide data pattern was increased to 8 bits since 8 bit + wide memory chips are becoming more common. + + A new test algorithm was added to improve detection of data + pattern sensitive errors. + + +Enhancements in v1.4 + Changes to the memory sizing code to avoid problems with some + motherboards where memtest would find more memory than actually + exists. + + Added support for a console serial port. (thanks to Doug Sisk) + + On-line commands are now available for configuring Memtest86 on + the fly (see On-line Commands). + + +Enhancements in v1.3 + Scrolling of memory errors is now provided. Previously, only one screen + of error information was displayed. + + Memtest86 can now be booted from any disk via lilo. + + Testing of up to 4gb of memory has been fixed is now enabled by default. + This capability was clearly broken in v1.2a and should work correctly + now but has not been fully tested (4gb PC's are a bit rare). + + The maximum memory size supported by the motherboard is now being + calculated correctly. In previous versions there were cases where not + all of memory would be tested and the maximum memory size supported + was incorrect. + + For some types of failures the good and bad values were reported to be + same with an Xor value of 0. This has been fixed by retaining the data + read from memory and not re-reading the bad data in the error reporting + routine. + + APM (advanced power management) is now disabled by Memtest86. This + keeps the screen from blanking while the test is running. + + Problems with enabling & disabling cache on some motherboards have been + corrected. + + +17) Acknowledgments +=================== +Memtest86 was developed by Chris Brady with the resources and assistance +listed below: + +- The initial versions of the source files bootsect.S, setup.S, head.S and + build.c are from the Linux 1.2.1 kernel and have been heavily modified. + +- Doug Sisk provided code to support a console connected via a serial port. + +- Code to create BadRAM patterns was provided by Rick van Rein. + +- Tests 5 and 8 are based on Robert Redelmeier's burnBX test. + +- Screen buffer code was provided by Jani Averbach. + +- Eric Biederman provided all of the feature content for version 3.0 + plus many bugfixes and significant code cleanup. + +- Major enhancements to hardware detection and reporting in version 3.2, + 3.3 pnd 3.4 rovided by Samuel Demeulemeester (from Memtest86+ v1.11, v1.60 + and v1.70). diff --git a/README.background b/README.background new file mode 100644 index 0000000..9c35250 --- /dev/null +++ b/README.background @@ -0,0 +1,156 @@ + The Anatomy & Physiology of Memtest86-SMP + ----------------------------------------- + +1. Binary layout + + --------------------------------------------------------------- + | bootsect.o | setup.o | head.o memtest_shared | + --------------------------------------------------------------- +Labels _start<-------memtest---------->_end + ----------------------------------------------------------- +addr 0 512 512+4*512 | + ----------------------------------------------------------- + +2. The following steps occur after we power on. + a. The bootsect.o code gets loaded at 0x7c00 + and copies + i. itself to 0x90000 + ii. setup.o to 0x90200 + iii. everything between _start and _end i.e memtest + to 0x10000 + b. jumps somewhere into the copied bootsect.o code at 0x90000 + ,does some trivial stuff and jumps to setup.o + c. setup.o puts the processor in protected mode, with a basic + gdt and idt and does a long jump to the start of the + memtest code (startup_32, see 4 below). The code and data + segment base address are all set to 0x0. So a linear + address range and no paging is enabled. + d. From now on we no longer required the bootsect.o and setup.o + code. +3. The code in memtest is compiled as position independent + code. Which implies that the code can be moved dynamically in + the address space and can still work. Since we are now in head.o, + which is compiled with PIC , we no longer should use absolute + addresses references while accessing functions or globals. + All symbols are stored in a table called Global Offset Table(GOT) + and %ebx is set to point to the base of that table. So to get/set + the value of a symbol we need to read (%ebx + symbolOffsetIntoGOT) to + get the symbol value. For eg. if foo is global varible the assembly + code to store %eax value into foo will be changed from + mov %eax, foo + to + mov %eax, foo@GOTOFF(%ebx) +4. (startup_32) The first step done in head.o is to change + the gdtr and idtr register values to point to the final(!) + gdt and ldt tables in head.o, since we can no longer use the + gdt and ldt tables in setup.o, and call the dynamic linker + stub in memtest_shared (see call _dl_start in head.S). This + dynamic linker stub relocates all the code in memtest w.r.t + the new base location i.e 0x1000. Finally we call the test_start() + 'C' routine. +5. The test_start() C routine is the main routine which lets the BSP + bring up the APs from their halt state, relocate the code + (if necessary) to new address, move the APs to the newly + relocated address and execute the tests. The BSP is the + master which controls the execution of the APs, and mostly + it is the one which manupulates the global variables. + i. we change the stack to a private per cpu stack. + (this step happens every time we move to a new location) + ii. We kick start the APs in the system by + a. Putting a temporary real mode code + (_ap_trampoline_start - _ap_trampoline_protmode) + at 0x9000, which puts the AP in protected mode and jumps + to _ap_trampoline_protmode in head.o. The code in + _ap_trampoline_protmode calls start_32 in head.o which + reinitialises the AP's gdt and idt to point to the + final(!) gdt and idt. (see step 4 above) + b. Since the APs also traverse through the same initialisation + code(startup_32 in head.o), the APs also call test_start(). + The APs just spin wait (see AP_SpinWaitStart) till the + are instructed by the BSP to jump to a new location, + which can either be a test execution or spin wait at a + new location. + iii. The base address at which memtest tries to execute as far + as possible is 0x2000. This is the lowest possible address + memtest can put itself at. So the next step is to + move to 0x2000, which it cannot directly, since copying + code to 0x2000 will override the existing code at 0x1000. + 0x2000 +sizeof(memtest) will usually be greater than 0x1000. + so we temporarily relocated to 0x200000 and then relocate + back to 0x2000. Every time the BSP relocates the code to the + new location, it pulls up the APs spin waiting at the old + location to spin wait at the corresponding relocated + spin wait location, by making them jump to the new + statup_32 relocated location(see 4 above). + Hence forth during the tests 0x200000 is the only place + we relocate to if we need to test a memory window + (see v. below to get a description of what a window is) + which includes address range 0x2000. + + Address map during normal execution. + -------------------------------------------------------------------- + | head.o memtest_shared | |RAM_END + -------------------------------------------------------------------- +Labels _start<-------memtest---------->_end + -------------------------------------------------------------------- +addr 0x0 0x2000 | Memory that is being tested.. |RAM_END + -------------------------------------------------------------------- + + Address map during relocated state. + -------------------------------------------------------------------- + | head.o memtest_shared | |RAM_END + -------------------------------------------------------------------- +Labels _start<-------memtest---------->_end + -------------------------------------------------------------------- +addr memory that is being tested... |0x200000 | |RAM_END + -------------------------------------------------------------------- + + iv. Once we are at 0x2000 we initialise the system, and + determine the memory map ,usually via the bios e820 map. + The sorted, and non-overlapping RAM page ranges are + placed in v->pmap[] array. This array is the reference + of the RAM memory map on the system. + v. The memory range(in page numbers) which the + memtest86 can test is partitioned into windows. + the current version of memtest86-smp has the capability + to test the memory from 0x0 - 0xFFFFFFFFF (max address + when pae mode is enabled). + We then compute the linear memory address ranges(called + segments) for the window we are currently about to + test. The windows are + a. 0 - 640K + b. (0x2000 + (_end - _start)) - 4G (since the code is at 0x2000). + c. >4G to test pae address range, each window with size + of 0x80000(2G), large enough to be mapped in one page directory + entry. So a window size of 0x80000 means we can map 1024 page + table entries, with page size of 2M(pae mode), with one + page directory entry. Something similar to kseg entry + in linux. The upper bound page number is 0x1000000 which + corresponds to linear address 0xFFFFFFFFF + 1 which uses + all the 36 address bits. + Each window is compared against the sorted & non-overlapping + e820 map which we have stored in v->pmap[] array, since all + memory in the selected window address range may correspond to + RAM or can be usable. A list of segments within the window is + created , which contain the usable portions of the window. + This is stored in v->mmap[] array. + vi. Once the v->mmap[] array populated, we have the list of + non-overlapping segments in the current window which are the + final address ranges that can be tested. The BSP executes the + test first and lets each AP execute the test one by one. Once + all the APs finish execting the same test, the BSP moves to the + next window follows the same procedure till all the windows + are done. Once all the windows are done, the BSP moves to the + next test. Before executing in any window the BSP checks if + the window overlaps with the code/data of memtest86, if so + tries to relocate to 0x200000. If the window includes both + 0x2000 as well as 0x200000 the BSP skips that window. + Looking at the window values the only time the memtest + relocates is when testing the 0 - 640K window. + +Known Issues: +* Memtest86-smp does not work on IBM-NUMA machines, x440 and friends. + +email comments to: +Kalyan Rajasekharuni<kc_rajasekharuni@yahoo.com> +Sub: Memtest86-SMP diff --git a/README.build-process b/README.build-process index a959e7b..19edfcf 100644 --- a/README.build-process +++ b/README.build-process @@ -1,39 +1,39 @@ -During memory testing memtest86+ relocates itself in memory so it can test the
-memory it was previously running from. memtest86+ is compiled as position mostly
-independent code. Some relocations records must be processed to achieve the
-affect of position independent code. A 16 bit loader is prepended to memtest86+
-so it can be loaded from a floppy, or from lilo.
-
-In restructuring the build process I had several goals. Maintainability and
-comprehsibility of the build process. Simplicity of the toolset. And the
-ability to build images bootable by both the legacy x86 bootloader,
-and images bootable by bootloaders that directly load static ELF images.
-
-With the ability to proecess relocation records, memtest.bin has been
-reduced in size from 84480 bytes to 49308 bytes. And now only requires one copy
-of memtest86+. A reduction in size of 35K. And the build process can now ignore
-the size of memtest86+.
-
-BIOS calls have been moved from setup.S to head.S making bootsect.S and
-setup.S exclusively for booting.
-
-memtest86+ is built in three stages. In the first stage the relocatable object
-files are built as with any program. In the second stage the relocatable object
-files are linked together into memtest_shared, a shared library version
-of memtest86+. In the third stage a raw memory image of memtest_shared is formed
-and linked into memtest.bin, and memtest.
-
-memtest.bin is the floppy/lilo bootable target.
-
-memtest is the ELF bootable target.
-
-Another major change is now data in the bss segment is also preserved
-when memtest86+ is relocated, and memtest86+ can be relocated to any address.
-
-The one thing to watch out for is pointers to data inside of memtest86+. Except
-for constant pointers to static data there is not enough information to generate
-relocation records for pointers so they will not change when memtest86+ is
-relocated, which might lead to nasty surpises.
-
-Eric Biederman <ebiederman@lnxi.com>
-
+During memory testing memtest86 relocates itself in memory so it can test the +memory it was previously running from. memtest86 is compiled as position mostly +independent code. Some relocations records must be processed to achieve the +affect of position independent code. A 16 bit loader is prepended to memtest86 +so it can be loaded from a floppy, or from lilo. + +In restructuring the build process I had several goals. Maintainability and +comprehsibility of the build process. Simplicity of the toolset. And the +ability to build images bootable by both the legacy x86 bootloader, +and images bootable by bootloaders that directly load static ELF images. + +With the ability to proecess relocation records, memtest.bin has been +reduced in size from 84480 bytes to 49308 bytes. And now only requires one copy +of memtest86. A reduction in size of 35K. And the build process can now ignore +the size of memtest86. + +BIOS calls have been moved from setup.S to head.S making bootsect.S and +setup.S exclusively for booting. + +memtest86 is built in three stages. In the first stage the relocatable object +files are built as with any program. In the second stage the relocatable object +files are linked together into memtest_shared, a shared library version +of memtest86. In the third stage a raw memory image of memtest_shared is formed +and linked into memtest.bin, and memtest. + +memtest.bin is the floppy/lilo bootable target. + +memtest is the ELF bootable target. + +Another major change is now data in the bss segment is also preserved +when memtest86 is relocated, and memtest86 can be relocated to any address. + +The one thing to watch out for is pointers to data inside of memtest86. Except +for constant pointers to static data there is not enough information to generate +relocation records for pointers so they will not change when memtest86 is +relocated, which might lead to nasty surpises. + +Eric Biederman <ebiederman@lnxi.com> + diff --git a/build-number.txt b/build-number.txt new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/build-number.txt @@ -0,0 +1 @@ +7 diff --git a/build.number b/build.number new file mode 100644 index 0000000..e110e8d --- /dev/null +++ b/build.number @@ -0,0 +1 @@ +617 diff --git a/build_number.h b/build_number.h new file mode 100644 index 0000000..d1f2abc --- /dev/null +++ b/build_number.h @@ -0,0 +1,9 @@ +#ifndef BUILD_NUMBER_STR +#define BUILD_NUMBER_STR "617" +#endif +#ifndef VERSION_STR +#define VERSION_STR "4.99617 - Thu May 3 11:45:57 CEST 2012" +#endif +#ifndef VERSION_STR_SHORT +#define VERSION_STR_SHORT "4.99617" +#endif diff --git a/buildnumber.mak b/buildnumber.mak new file mode 100644 index 0000000..8d5b85d --- /dev/null +++ b/buildnumber.mak @@ -0,0 +1,10 @@ +# Create an auto-incrementing build number. + +BUILD_NUMBER_LDFLAGS = -Xlinker --defsym -Xlinker __BUILD_DATE=$$(date +'%Y%m%d') +BUILD_NUMBER_LDFLAGS += -Xlinker --defsym -Xlinker __BUILD_NUMBER=$$(cat $(BUILD_NUMBER_FILE)) + +# Build number file. Increment if any object file changes. +$(BUILD_NUMBER_FILE): $(OBJS) + @if ! test -f $(BUILD_NUMBER_FILE); then echo 0 > $(BUILD_NUMBER_FILE); fi + @echo $$(($$(cat $(BUILD_NUMBER_FILE)) + 1)) > $(BUILD_NUMBER_FILE) + @@ -1,9 +1,25 @@ -Memtest86+ V4.20 changelog
---------------------------
+Memtest86+ V5.01 changelog
+----------------------------
- - Added failsafe mode (F1 at startup)
- - Added support for Intel "Sandy Bridge" CPU
- - Added support for AMD "fusion" CPU
- - Added Coreboot "table forward" support
- - Corrected some memory brand not detected
- - Various bug fixes
\ No newline at end of file + - Added support for up to 2 TB of RAM on X64 CPUs
+ - Added experimental SMT support up to 32 cores
+ - Added complete detection for memory controllers.
+ - Added Motherboard Manufacturer & Model reporting
+ - Added CPU temperature reporting
+ - Added enhanced Fail Safe Mode (Press F1 at startup)
+ - Added support for Intel "Sandy Bridge-E" CPUs
+ - Added support for Intel "Ivy Bridge" CPUs
+ - Added preliminary support for Intel "Haswell" CPUs
+ - Added preliminary support for Intel "Haswell-ULT" CPUs
+ - Added support for AMD "Kabini" (K16) CPUs
+ - Added support for AMD "Bulldozer" CPUs
+ - Added support for AMD "Trinity" CPUs
+ - Added support for AMD E-/C-/G-/Z- "Bobcat" CPUs
+ - Added support for Intel Atom "Pineview" CPUs
+ - Added support for Intel Atom "Cedar Trail" CPUs
+ - Added SPD detection on most AMD Chipsets
+ - Enforced Coreboot support
+ - Optimized run time for faster memory error detection
+ - Rewriten lots of memory timings detection code
+ - Corrected bugs, bugs and more bugs
+
@@ -3,30 +3,36 @@ * Released under version 2 of the Gnu Public License. * By Chris Brady * ---------------------------------------------------- - * MemTest86+ V4.00 Specific code (GPL V2.0) + * MemTest86+ V5.00 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.x86-secret.com - http://www.memtest.org */ #include "test.h" #include "screen_buffer.h" -#include "controller.h" #include "dmi.h" -#define ITER 20 extern int bail, beepmode; extern struct tseq tseq[]; extern short e820_nr; -extern char memsz_mode; -extern int find_ticks_for_pass(); -//void performance(); +void performance(); +extern volatile short cpu_mode; +extern volatile int test; +extern void find_chunks(); +extern volatile short start_seq; +extern short restart_flag; +extern short onepass; +extern short btflag; + +extern void get_list(int x, int y, int len, char *buf); char save[2][POP_H][POP_W]; char save2[2][POP2_H][POP2_W]; void get_config() { - int flag = 0, sflag = 0, i, prt = 0; - int reprint_screen = 0; + int flag = 0, sflag = 0, i, j, k, n, m, prt = 0; + int reprint_screen = 0; + char cp[64]; ulong page; popup(); @@ -35,14 +41,12 @@ void get_config() cprint(POP_Y+1, POP_X+2, "Settings:"); cprint(POP_Y+3, POP_X+6, "(1) Test Selection"); cprint(POP_Y+4, POP_X+6, "(2) Address Range"); - cprint(POP_Y+5, POP_X+6, "(3) Memory Sizing"); - cprint(POP_Y+6, POP_X+6, "(4) Error Report Mode"); - cprint(POP_Y+7, POP_X+6, "(5) Show DMI Memory Info"); - cprint(POP_Y+8, POP_X+6, "(6) ECC Mode"); - cprint(POP_Y+9, POP_X+6, "(7) Restart"); - cprint(POP_Y+10, POP_X+6, "(8) Refresh Screen"); - cprint(POP_Y+11, POP_X+6, "(9) Display SPD Data"); - cprint(POP_Y+12, POP_X+6, "(0) Continue"); + cprint(POP_Y+5, POP_X+6, "(3) Error Report Mode"); + cprint(POP_Y+6, POP_X+6, "(4) Core Selection"); + cprint(POP_Y+7, POP_X+6, "(5) Refresh Screen"); + cprint(POP_Y+8, POP_X+6, "(6) Display DMI Data"); + cprint(POP_Y+9, POP_X+6, "(7) Display SPD Data"); + cprint(POP_Y+11, POP_X+6, "(0) Continue"); /* Wait for key release */ /* Fooey! This nuts'es up the serial input. */ @@ -55,9 +59,8 @@ void get_config() cprint(POP_Y+3, POP_X+6, "(1) Default Tests"); cprint(POP_Y+4, POP_X+6, "(2) Skip Current Test"); cprint(POP_Y+5, POP_X+6, "(3) Select Test"); - cprint(POP_Y+6, POP_X+6, "(4) Select Bit Fade Test"); - //cprint(POP_Y+7, POP_X+6, "(5) Select Uncached Test"); - cprint(POP_Y+8, POP_X+6, "(0) Continue"); + cprint(POP_Y+6, POP_X+6, "(4) Enter Test List"); + cprint(POP_Y+7, POP_X+6, "(0) Cancel"); if (v->testsel < 0) { cprint(POP_Y+3, POP_X+5, ">"); } else { @@ -67,14 +70,14 @@ void get_config() while (!sflag) { switch(get_key()) { case 2: - /* Default */ - if (v->testsel >= 9) { - bail++; + /* Default - All tests */ + i = 0; + while (tseq[i].cpu_sel) { + tseq[i].sel = 1; + i++; } - v->testsel = -1; find_ticks_for_pass(); sflag++; - cprint(LINE_INFO, COL_TST, "Std"); break; case 3: /* Skip test */ @@ -87,47 +90,79 @@ void get_config() cprint(POP_Y+1, POP_X+3, "Test Selection:"); cprint(POP_Y+4, POP_X+5, - "Test Number [0-9]: "); - i = getval(POP_Y+4, POP_X+24, 0); - if (i <= 9) { - if (i != v->testsel) { - v->pass = -1; - v->test = -1; + "Test Number [1-11]: "); + n = getval(POP_Y+4, POP_X+24, 0) - 1; + if (n <= 11) + { + /* Deselect all tests */ + i = 0; + while (tseq[i].cpu_sel) { + tseq[i].sel = 0; + i++; + } + /* Now set the selection */ + tseq[n].sel = 1; + v->pass = -1; + test = n; + find_ticks_for_pass(); + sflag++; + bail++; } - v->testsel = i; - } - find_ticks_for_pass(); - sflag++; - bail++; - cprint(LINE_INFO, COL_TST, "#"); - dprint(LINE_INFO, COL_TST+1, i, 2, 1); break; case 5: - if (v->testsel != 9) { - v->pass = -1; - v->test = -1; + /* Enter a test list */ + popclear(); + cprint(POP_Y+1, POP_X+3, + "Enter a comma separated list"); + cprint(POP_Y+2, POP_X+3, + "of tests to execute:"); + cprint(POP_Y+5, POP_X+5, "List: "); + /* Deselect all tests */ + k = 0; + while (tseq[k].cpu_sel) { + tseq[k].sel = 0; + k++; } - v->testsel = 9; - find_ticks_for_pass(); - sflag++; - bail++; - cprint(LINE_INFO, COL_TST, "#"); - dprint(LINE_INFO, COL_TST+1, 9, 3, 1); - break; -/* - case 6: - if (v->testsel != 10) { - v->pass = -1; - v->test = -1; + + /* Get the list */ + for (i=0; i<64; i++) cp[i] = 0; + get_list(POP_Y+5, POP_X+10, 64, cp); + + /* Now enable all of the tests in the + * list */ + i = j = m = 0; + while (1) { + if (isdigit(cp[i])) { + n = cp[i]-'0'; + j = j*10 + n; + i++; + if (cp[i] == ',' || cp[i] == 0){ + if (j < k) { + tseq[j].sel = 1; + m++; + } + if (cp[i] == 0) break; + j = 0; + i++; + } + } } - v->testsel = 9+1; + + /* If we didn't select at least one + * test turn them all back on */ + if (m == 0) { + k = 0; + while (tseq[k].cpu_sel) { + tseq[k].sel = 1; + k++; + } + } + v->pass = -1; + test = n; find_ticks_for_pass(); sflag++; - bail++; - cprint(LINE_INFO, COL_TST, "#"); - dprint(LINE_INFO, COL_TST+1, 10, 3, 1); + bail++; break; -*/ case 11: case 57: sflag++; @@ -143,7 +178,7 @@ void get_config() cprint(POP_Y+3, POP_X+6, "(1) Set Lower Limit"); cprint(POP_Y+4, POP_X+6, "(2) Set Upper Limit"); cprint(POP_Y+5, POP_X+6, "(3) Test All Memory"); - cprint(POP_Y+6, POP_X+6, "(0) Continue"); + cprint(POP_Y+6, POP_X+6, "(0) Cancel"); wait_keyup(); while (!sflag) { switch(get_key()) { @@ -160,10 +195,11 @@ void get_config() page = getval(POP_Y+6, POP_X+9, 12); if (page + 1 <= v->plim_upper) { v->plim_lower = page; - v->test--; + test--; bail++; } adj_mem(); + find_chunks(); find_ticks_for_pass(); sflag++; break; @@ -180,20 +216,23 @@ void get_config() page = getval(POP_Y+6, POP_X+9, 12); if (page - 1 >= v->plim_lower) { v->plim_upper = page; - v->test--; bail++; + test--; } adj_mem(); + find_chunks(); find_ticks_for_pass(); sflag++; break; case 4: /* All of memory */ v->plim_lower = 0; - v->plim_upper = v->pmap[v->msegs - 1].end; - v->test--; + v->plim_upper = + v->pmap[v->msegs - 1].end; + test--; bail++; adj_mem(); + find_chunks(); find_ticks_for_pass(); sflag++; break; @@ -207,59 +246,20 @@ void get_config() popclear(); break; case 4: - /* 3 - Memory Sizing */ - popclear(); - cprint(POP_Y+1, POP_X+2, "Memory Sizing:"); - cprint(POP_Y+3, POP_X+6, "(1) BIOS - Std"); - cprint(POP_Y+4, POP_X+6, "(2) Probe"); - cprint(POP_Y+5, POP_X+6, "(0) Continue"); - if(!e820_nr){ - if (memsz_mode == SZ_MODE_BIOS) { - cprint(POP_Y+3, POP_X+5, ">"); - } else { - cprint(POP_Y+4, POP_X+5, ">"); - } - } - wait_keyup(); - while (!sflag) { - switch(get_key()) { - case 2: - memsz_mode = SZ_MODE_BIOS; - wait_keyup(); - restart(); - - break; - case 3: - memsz_mode = SZ_MODE_PROBE; - wait_keyup(); - restart(); - - break; - case 11: - case 57: - /* 0/CR - Continue */ - sflag++; - break; - } - } - popclear(); - break; - case 5: - /* 4 - Show error Mode */ + /* Error Mode */ popclear(); cprint(POP_Y+1, POP_X+2, "Printing Mode:"); cprint(POP_Y+3, POP_X+6, "(1) Error Summary"); cprint(POP_Y+4, POP_X+6, "(2) Individual Errors"); cprint(POP_Y+5, POP_X+6, "(3) BadRAM Patterns"); cprint(POP_Y+6, POP_X+6, "(4) Error Counts Only"); - cprint(POP_Y+7, POP_X+6, "(5) DMI Device Name"); - cprint(POP_Y+8, POP_X+6, "(6) Beep on Error"); - cprint(POP_Y+10, POP_X+6, "(0) Cancel"); + cprint(POP_Y+7, POP_X+6, "(5) Beep on Error"); + cprint(POP_Y+8, POP_X+6, "(0) Cancel"); cprint(POP_Y+3+v->printmode, POP_X+5, ">"); - if (beepmode) { cprint(POP_Y+8, POP_X+5, ">"); } + if (beepmode) { cprint(POP_Y+7, POP_X+5, ">"); } wait_keyup(); while (!sflag) { - switch(get_key()) { + switch(get_key()) { case 2: /* Error Summary */ v->printmode=PRINTMODE_SUMMARY; @@ -289,16 +289,10 @@ void get_config() sflag++; break; case 6: - /* Error Counts Only */ - v->printmode=PRINTMODE_DMI; - v->erri.hdr_flag = 0; - sflag++; - break; - case 7: /* Set Beep On Error mode */ beepmode = !beepmode; sflag++; - break; + break; case 11: case 57: /* 0/CR - Continue */ @@ -308,34 +302,42 @@ void get_config() } popclear(); break; - case 6: - /* Display DMI Memory Info */ - pop2up(); - print_dmi_info(); - pop2down(); - break; - case 7: - /* 6 - ECC Polling Mode */ + case 5: + /* CPU Mode */ + reprint_screen = 1; popclear(); - cprint(POP_Y+1, POP_X+2, "ECC Polling Mode:"); - cprint(POP_Y+3, POP_X+6, "(1) Recommended"); - cprint(POP_Y+4, POP_X+6, "(2) On"); - cprint(POP_Y+5, POP_X+6, "(3) Off"); - cprint(POP_Y+6, POP_X+6, "(0) Continue"); + cprint(POP_Y+1, POP_X+2, "CPU Selection Mode:"); + cprint(POP_Y+3, POP_X+6, "(1) Parallel (All)"); + cprint(POP_Y+4, POP_X+6, "(2) Round Robin (RRb)"); + cprint(POP_Y+5, POP_X+6, "(3) Sequential (Seq)"); + cprint(POP_Y+6, POP_X+6, "(0) Cancel"); + cprint(POP_Y+2+cpu_mode, POP_X+5, ">"); wait_keyup(); while(!sflag) { switch(get_key()) { case 2: - set_ecc_polling(-1); + if (cpu_mode != CPM_ALL) bail++; + cpu_mode = CPM_ALL; sflag++; + popdown(); + cprint(9,34,"All"); + popup(); break; case 3: - set_ecc_polling(1); + if (cpu_mode != CPM_RROBIN) bail++; + cpu_mode = CPM_RROBIN; sflag++; + popdown(); + cprint(9,34,"RRb"); + popup(); break; case 4: - set_ecc_polling(0); + if (cpu_mode != CPM_SEQ) bail++; + cpu_mode = CPM_SEQ; sflag++; + popdown(); + cprint(9,34,"Seq"); + popup(); break; case 11: case 57: @@ -346,15 +348,18 @@ void get_config() } popclear(); break; - case 8: - wait_keyup(); - restart(); - break; - case 9: + case 6: reprint_screen = 1; flag++; break; - case 10: + case 7: + /* Display DMI Memory Info */ + pop2up(); + print_dmi_info(); + pop2down(); + break; + case 8: + /* Display SPD Data */ popdown(); show_spd(); popup(); @@ -372,12 +377,11 @@ void get_config() if (prt) { printpatn(); } - if (reprint_screen){ - tty_print_screen(); - } + if (reprint_screen){ + tty_print_screen(); + } } - void popup() { int i, j; @@ -386,11 +390,11 @@ void popup() for (i=POP_Y; i<POP_Y + POP_H; i++) { for (j=POP_X; j<POP_X + POP_W; j++) { pp = (char *)(SCREEN_ADR + (i * 160) + (j * 2)); - save[0][i-POP_Y][j-POP_X] = *pp; /* Save screen */ - set_scrn_buf(i, j, ' '); - *pp = ' '; /* Clear */ + save[0][i-POP_Y][j-POP_X] = *pp; /* Save screen */ + set_scrn_buf(i, j, ' '); + *pp = ' '; /* Clear */ pp++; - save[1][i-POP_Y][j-POP_X] = *pp; + save[1][i-POP_Y][j-POP_X] = *pp; *pp = 0x07; /* Change Background to black */ } } @@ -406,7 +410,7 @@ void popdown() for (j=POP_X; j<POP_X + POP_W; j++) { pp = (char *)(SCREEN_ADR + (i * 160) + (j * 2)); *pp = save[0][i-POP_Y][j-POP_X]; /* Restore screen */ - set_scrn_buf(i, j, save[0][i-POP_Y][j-POP_X]); + set_scrn_buf(i, j, save[0][i-POP_Y][j-POP_X]); pp++; *pp = save[1][i-POP_Y][j-POP_X]; /* Restore color */ } @@ -423,14 +427,13 @@ void popclear() for (j=POP_X; j<POP_X + POP_W; j++) { pp = (char *)(SCREEN_ADR + (i * 160) + (j * 2)); *pp = ' '; /* Clear popup */ - set_scrn_buf(i, j, ' '); + set_scrn_buf(i, j, ' '); pp++; } } tty_print_region(POP_Y, POP_X, POP_Y+POP_H, POP_X+POP_W); } - void pop2up() { int i, j; @@ -483,16 +486,6 @@ void pop2clear() tty_print_region(POP2_Y, POP2_X, POP2_Y+POP2_H, POP2_X+POP2_W); } -void clear_screen() -{ - int i; - volatile char *pp; - - for(i=0, pp=(char *)(SCREEN_ADR); i<80*24; i++) { - *pp++ = ' '; - *pp++ = 0x07; - } -} void adj_mem(void) { @@ -536,58 +529,3 @@ void adj_mem(void) } } } - -/* -void performance() -{ - extern int l1_cache, l2_cache; - ulong speed; - int i; - - popclear(); - - cprint(POP_Y+1, POP_X+1, " Read Write Copy"); - cprint(POP_Y+3, POP_X+1, "L1 Cache:"); - speed=memspeed((ulong)mapping(0x100), (l1_cache/4)*1024, 500, MS_READ); - dprint(POP_Y+3, POP_X+10, speed, 6, 0); - speed=memspeed((ulong)mapping(0x100), (l1_cache/4)*1024, 50, MS_WRITE); - dprint(POP_Y+3, POP_X+17, speed, 6, 0); - speed=memspeed((ulong)mapping(0x100), (l1_cache/4)*1024, 50, MS_COPY); - dprint(POP_Y+3, POP_X+24, speed, 6, 0); - - if (l2_cache < l1_cache) { - i = l1_cache / 4 + l2_cache / 4; - } else { - i = l1_cache; - } - cprint(POP_Y+5, POP_X+1, "L2 Cache:"); - speed=memspeed((ulong)mapping(0x100), i*1024, 500, MS_READ); - dprint(POP_Y+5, POP_X+10, speed, 6, 0); - speed=memspeed((ulong)mapping(0x100), i*1024, 50, MS_WRITE); - dprint(POP_Y+5, POP_X+17, speed, 6, 0); - speed=memspeed((ulong)mapping(0x100), i*1024, 50, MS_COPY); - dprint(POP_Y+5, POP_X+24, speed, 6, 0); - - // Determine memory speed. To find the memory spped we use - // A block size that is 5x the sum of the L1 and L2 caches - i = (l2_cache + l1_cache) * 5; - - // Make sure that we have enough memory to do the test - if ((1 + (i * 2)) > (v->plim_upper << 2)) { - i = ((v->plim_upper <<2) - 1) / 2; - } - - - cprint(POP_Y+7, POP_X+1, "Memory:"); - speed=memspeed((ulong)mapping(0x100), i*1024, 500, MS_READ); - dprint(POP_Y+7, POP_X+10, speed, 6, 0); - speed=memspeed((ulong)mapping(0x100), i*1024, 50, MS_WRITE); - dprint(POP_Y+7, POP_X+17, speed, 6, 0); - speed=memspeed((ulong)mapping(0x100), i*1024, 50, MS_COPY); - dprint(POP_Y+7, POP_X+24, speed, 6, 0); - - wait_keyup(); - while (get_key() == 0); - popclear(); -} -*/ @@ -1,11 +1,27 @@ -/* config.h - MemTest-86 Version 3.0 +/* + * MemTest86+ V5 Specific code (GPL V2.0) + * By Samuel DEMEULEMEESTER, sdemeule@memtest.org + * http://www.canardpc.com - http://www.memtest.org + * ------------------------------------------------ + * config.h - MemTest-86 Version 3.3 * * Compile time configuration options * * Released under version 2 of the Gnu Public License. - * By Chris Brady, cbrady@sgi.com + * By Chris Brady */ +/* CONSERVATIVE_SMP - If set to 0, SMP will be enabled by default */ +/* Might be enabled in future revision after extensive testing */ +/* In all cases, SMP is disabled by defaut on server platform */ +#define CONSERVATIVE_SMP 1 + +/* BEEP_MODE - Beep on error. Default off, Change to 1 to enable */ +#define BEEP_MODE 0 + +/* BEEP_END_NO_ERROR - Beep at end of each pass without error. Default off, Change to 1 to enable */ +#define BEEP_END_NO_ERROR 0 + /* PARITY_MEM - Enables support for reporting memory parity errors */ /* Experimental, normally enabled */ #define PARITY_MEM @@ -21,18 +37,6 @@ /* SERIAL_BAUD_RATE - Baud rate for the serial console */ #define SERIAL_BAUD_RATE 9600 -/* START_FAIL_SAFE - Default 0 = normal. Change to 1 to always start in fail safe mode */ -#define START_FAIL_SAFE 0 - -/* BEEP_MODE - Beep on error. Default off, Change to 1 to enable */ -#define BEEP_MODE 0 - -/* BEEP_END_NO_ERROR - Beep at end of each pass without error. Default off, Change to 1 to enable */ -#define BEEP_END_NO_ERROR 0 - -/* FIRST_PASS_HALF_ITERATIONS - First pass twice faster / half iterations. Change to 0 to disable */ -#define FIRST_PASS_HALF_ITERATIONS 1 - /* SCRN_DEBUG - extra check for SCREEN_BUFFER */ /* #define SCRN_DEBUG */ diff --git a/controller.c b/controller.c index 9009996..f4f7371 100644 --- a/controller.c +++ b/controller.c @@ -1,21 +1,20 @@ -/* controller.c - MemTest-86 Version 3.0 - * - * Released under version 2 of the Gnu Public License. - * By Chris Brady, cbrady@sgi.com - * ---------------------------------------------------- - * MemTest86+ V4.20 Specific code (GPL V2.0) +/* + * MemTest86+ V5 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.canardpc.com - http://www.memtest.org */ -#include "defs.h" +//#include "defs.h" #include "config.h" -#include "test.h" +//#include "test.h" #include "pci.h" #include "controller.h" #include "spd.h" #include "test.h" - +#include "stdint.h" +#include "cpuid.h" +#include "msr.h" +#include "dmi.h" int col, col2; int nhm_bus = 0x3F; @@ -23,18 +22,17 @@ int nhm_bus = 0x3F; extern ulong extclock; extern unsigned long imc_type; extern struct cpu_ident cpu_id; -extern int fail_safe; - +/* #define rdmsr(msr,val1,val2) \ __asm__ __volatile__("rdmsr" \ : "=a" (val1), "=d" (val2) \ - : "c" (msr)) + : "c" (msr) : "edi") #define wrmsr(msr,val1,val2) \ __asm__ __volatile__("wrmsr" \ - : /* no outputs */ \ - : "c" (msr), "a" (val1), "d" (val2)) - + : \ + : "c" (msr), "a" (val1), "d" (val2) : "edi") +*/ /* controller ECC capabilities and mode */ #define __ECC_UNEXPECTED 1 /* Unknown ECC capability present */ #define __ECC_DETECT 2 /* Can detect ECC errors */ @@ -74,115 +72,187 @@ static struct ecc_info { .mode = ECC_UNKNOWN, }; -struct pci_memory_controller { - unsigned vendor; - unsigned device; - char *name; - int tested; - void (*poll_fsb)(void); - void (*poll_timings)(void); - void (*setup_ecc)(void); - void (*poll_errors)(void); -}; +void coretemp(void) +{ + unsigned int msrl, msrh; + unsigned int tjunc, tabs, tnow; + unsigned long rtcr; + double amd_raw_temp; + + // Only enable coretemp if IMC is known + if(imc_type == 0) { return; } + + tnow = 0; + + // Intel CPU + if(cpu_id.vend_id.char_array[0] == 'G' && cpu_id.max_cpuid >= 6) + { + if(cpu_id.dts_pmp & 1){ + rdmsr(MSR_IA32_THERM_STATUS, msrl, msrh); + tabs = ((msrl >> 16) & 0x7F); + rdmsr(MSR_IA32_TEMPERATURE_TARGET, msrl, msrh); + tjunc = ((msrl >> 16) & 0x7F); + if(tjunc < 50 || tjunc > 125) { tjunc = 90; } // assume Tjunc = 90°C if boggus value received. + tnow = tjunc - tabs; + dprint(LINE_CPU+1, 30, v->check_temp, 3, 0); + v->check_temp = tnow; + } + return; + } + + // AMD CPU + if(cpu_id.vend_id.char_array[0] == 'A' && cpu_id.vers.bits.extendedFamily > 0) + { + pci_conf_read(0, 24, 3, 0xA4, 4, &rtcr); + amd_raw_temp = ((rtcr >> 21) & 0x7FF); + v->check_temp = (int)(amd_raw_temp / 8); + dprint(LINE_CPU+1, 30, v->check_temp, 3, 0); + } + + +} + +void print_cpu_line(float dram_freq, float fsb_freq, int ram_type) +{ + int cur_col = COL_SPEC; + + cprint(LINE_CPU, cur_col, "RAM: "); + cur_col += 5; + dprint(LINE_CPU, cur_col, dram_freq, 4, 1); + cur_col += 4; + cprint(LINE_CPU, cur_col, "MHz ("); + cur_col += 5; + + switch(ram_type) + { + default: + case 1: + cprint(LINE_CPU, cur_col, "DDR-"); + cur_col += 4; + break; + case 2: + cprint(LINE_CPU, cur_col, "DDR2-"); + cur_col += 5; + break; + case 3: + cprint(LINE_CPU, cur_col, "DDR3-"); + cur_col += 5; + break; + } + + if(dram_freq < 500) + { + dprint(LINE_CPU, cur_col, dram_freq*2, 3, 0); + cur_col += 3; + } else { + dprint(LINE_CPU, cur_col, dram_freq*2, 4, 0); + cur_col += 4; + } + cprint(LINE_CPU, cur_col, ")"); + cur_col++; + + if(fsb_freq > 10) + { + cprint(LINE_CPU, cur_col, " - BCLK: "); + cur_col += 9; + + dprint(LINE_CPU, cur_col, fsb_freq, 3, 0); + } + +} -void print_timings_info(float cas, int rcd, int rp, int ras) { +void print_ram_line(float cas, int rcd, int rp, int ras, int chan) +{ + int cur_col = COL_SPEC; - /* Now, we could print some additionnals timings infos) */ - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; + cprint(LINE_RAM, cur_col, "Timings: CAS "); + cur_col += 13; // CAS Latency (tCAS) if (cas == 1.5) { - cprint(LINE_CPU+6, col2, "1.5"); col2 += 3; + cprint(LINE_RAM, cur_col, "1.5"); cur_col += 3; } else if (cas == 2.5) { - cprint(LINE_CPU+6, col2, "2.5"); col2 += 3; + cprint(LINE_RAM, cur_col, "2.5"); cur_col += 3; } else if (cas < 10) { - dprint(LINE_CPU+6, col2, cas, 1, 0); col2 += 1; + dprint(LINE_RAM, cur_col, cas, 1, 0); cur_col += 1; } else { - dprint(LINE_CPU+6, col2, cas, 2, 0); col2 += 2; + dprint(LINE_RAM, cur_col, cas, 2, 0); cur_col += 2; } - cprint(LINE_CPU+6, col2, "-"); col2 += 1; + cprint(LINE_RAM, cur_col, "-"); cur_col += 1; // RAS-To-CAS (tRCD) if (rcd < 10) { - dprint(LINE_CPU+6, col2, rcd, 1, 0); - col2 += 1; + dprint(LINE_RAM, cur_col, rcd, 1, 0); + cur_col += 1; } else { - dprint(LINE_CPU+6, col2, rcd, 2, 0); - col2 += 2; + dprint(LINE_RAM, cur_col, rcd, 2, 0); + cur_col += 2; } - cprint(LINE_CPU+6, col2, "-"); col2 += 1; + cprint(LINE_RAM, cur_col, "-"); cur_col += 1; // RAS Precharge (tRP) if (rp < 10) { - dprint(LINE_CPU+6, col2, rp, 1, 0); - col2 += 1; + dprint(LINE_RAM, cur_col, rp, 1, 0); + cur_col += 1; } else { - dprint(LINE_CPU+6, col2, rp, 2, 0); - col2 += 2; + dprint(LINE_RAM, cur_col, rp, 2, 0); + cur_col += 2; } - cprint(LINE_CPU+6, col2, "-"); col2 += 1; + cprint(LINE_RAM, cur_col, "-"); cur_col += 1; // RAS Active to precharge (tRAS) if (ras < 10) { - dprint(LINE_CPU+6, col2, ras, 1, 0); - col2 += 2; + dprint(LINE_RAM, cur_col, ras, 1, 0); + cur_col += 1; } else { - dprint(LINE_CPU+6, col2, ras, 2, 0); - col2 += 3; + dprint(LINE_RAM, cur_col, ras, 2, 0); + cur_col += 2; } - -} - -void print_fsb_info(float val, const char *text_fsb, const char *text_ddr) { - - int i; - - cprint(LINE_CPU+6, col2, "Settings: "); - col2 += 10; - cprint(LINE_CPU+6, col2, text_fsb); - col2 += 6; - dprint(LINE_CPU+6, col2, val ,3 ,0); - col2 += 3; - cprint(LINE_CPU+6, col2 +1, "MHz ("); - col2 += 6; - - cprint(LINE_CPU+6, col2, text_ddr); - for(i = 0; text_ddr[i] != '\0'; i++) { col2++; } - - if(val < 500) { - dprint(LINE_CPU+6, col2, val*2 ,3 ,0); - col2 += 3; - } else { - dprint(LINE_CPU+6, col2, val*2 ,4 ,0); - col2 += 4; + + + switch(chan) + { + case 0: + break; + case 1: + cprint(LINE_RAM, cur_col, " @ 64-bit Mode"); + break; + case 2: + cprint(LINE_RAM, cur_col, " @ 128-bit Mode"); + break; + case 3: + cprint(LINE_RAM, cur_col, " @ 192-bit Mode"); + break; + case 4: + cprint(LINE_RAM, cur_col, " @ 256-bit Mode"); + break; } - cprint(LINE_CPU+6, col2, ")"); - col2 += 1; } - - static void poll_fsb_nothing(void) { -/* Code to run for no specific fsb detection */ + + char *name; + + /* Print the controller name */ + name = controllers[ctrl.index].name; + cprint(LINE_CPU, COL_SPEC, "Chipset: "); + cprint(LINE_CPU, COL_SPEC+9, name); return; } static void poll_timings_nothing(void) { -/* Code to run for no specific timings detection */ + char *ram_type; + + /* Print the controller name */ + ram_type = controllers[ctrl.index].ram_type; + cprint(LINE_RAM, COL_SPEC, "RAM Type: "); + cprint(LINE_RAM, COL_SPEC+10, ram_type); return; } -static void poll_fsb_failsafe(void) -{ -/* Code to run for no specific fsb detection */ - cprint(LINE_CPU+5, 0, "Chipset/IMC : ***FAIL SAFE***FAIL SAFE***FAIL SAFE***FAIL SAFE***FAIL SAFE***"); - cprint(LINE_CPU+6, 0, "*** Memtest86+ is running in fail safe mode. Same reliability, less details ***"); - return; -} static void setup_nothing(void) { ctrl.cap = ECC_NONE; @@ -199,18 +269,14 @@ static void poll_nothing(void) static void setup_wmr(void) { - - // Activate MMR I/O ulong dev0; - ctrl.cap = ECC_CORRECT; - + + // Activate MMR I/O pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); if (!(dev0 & 0x1)) { pci_conf_write( 0, 0, 0, 0x48, 1, dev0 | 1); } - ctrl.mode = ECC_NONE; - } @@ -261,7 +327,6 @@ static void setup_nhm32(void) ctrl.mode = ECC_NONE; /* First, locate the PCI bus where the MCH is located */ - for(i = 0; i < sizeof(possible_nhm_bus); i++) { pci_conf_read( possible_nhm_bus[i], 3, 4, 0x00, 2, &vid); pci_conf_read( possible_nhm_bus[i], 3, 4, 0x02, 2, &did); @@ -270,7 +335,7 @@ static void setup_nhm32(void) if(vid == 0x8086 && did >= 0x2C00) { nhm_bus = possible_nhm_bus[i]; } -} + } /* Now, we have the last IMC bus number in nhm_bus */ /* Check for ECC & Scrub */ @@ -287,7 +352,6 @@ static void setup_nhm32(void) static void setup_amd64(void) { - static const int ddim[] = { ECC_NONE, ECC_CORRECT, ECC_RESERVED, ECC_CHIPKILL }; unsigned long nbxcfg; unsigned int mcgsrl; @@ -301,8 +365,7 @@ static void setup_amd64(void) /* Check First if ECC DRAM Modules are used */ pci_conf_read(0, 24, 2, 0x90, 4, &dramcl); - - if (((cpu_id.ext >> 16) & 0xF) >= 4) { + if (cpu_id.vers.bits.extendedModel >= 4) { /* NEW K8 0Fh Family 90 nm */ if ((dramcl >> 19)&1){ @@ -350,24 +413,24 @@ static void setup_k10(void) unsigned long dramcl; ulong msr_low, msr_high; - /* All AMD64 support Chipkill */ + // All AMD64 support Chipkill */ ctrl.cap = ECC_CHIPKILL; - /* Check First if ECC DRAM Modules are used */ + // Check First if ECC DRAM Modules are used */ pci_conf_read(0, 24, 2, 0x90, 4, &dramcl); if ((dramcl >> 19)&1){ - /* Fill in the correct memory capabilites */ + // Fill in the correct memory capabilites */ pci_conf_read(0, 24, 3, 0x44, 4, &nbxcfg); ctrl.mode = ddim[(nbxcfg >> 22)&3]; } else { ctrl.mode = ECC_NONE; } - /* Enable NB ECC Logging by MSR Write */ + // Enable NB ECC Logging by MSR Write */ rdmsr(0x017B, mcgsrl, mcgsth); wrmsr(0x017B, 0x10, mcgsth); - /* Clear any previous error */ + // Clear any previous error */ pci_conf_read(0, 24, 3, 0x4C, 4, &mcanb); pci_conf_write(0, 24, 3, 0x4C, 4, mcanb & 0x7FFFFFFF ); @@ -378,6 +441,19 @@ static void setup_k10(void) } +static void setup_apu(void) +{ + + ulong msr_low, msr_high; + + /* Enable ECS */ + rdmsr(0xC001001F, msr_low, msr_high); + wrmsr(0xC001001F, msr_low, (msr_high | 0x4000)); + rdmsr(0xC001001F, msr_low, msr_high); + +} + +/* static void poll_amd64(void) { @@ -389,42 +465,43 @@ static void poll_amd64(void) pci_conf_read(0, 24, 3, 0x4C, 4, &mcanb); if (((mcanb >> 31)&1) && ((mcanb >> 14)&1)) { - /* Find out about the first correctable error */ - /* Syndrome code -> bits use a complex matrix. Will add this later */ - /* Read the error location */ + // Find out about the first correctable error + // Syndrome code -> bits use a complex matrix. Will add this later + // Read the error location pci_conf_read(0, 24, 3, 0x50, 4, &mcanb_add); - /* Read the syndrome */ + // Read the syndrome celog_syndrome = (mcanb >> 15)&0xFF; - /* Parse the error location */ + // Parse the error location page = (mcanb_add >> 12); offset = (mcanb_add >> 3) & 0xFFF; - /* Report the error */ + // Report the error print_ecc_err(page, offset, 1, celog_syndrome, 0); - /* Clear the error registers */ + // Clear the error registers pci_conf_write(0, 24, 3, 0x4C, 4, mcanb & 0x7FFFFFFF ); } if (((mcanb >> 31)&1) && ((mcanb >> 13)&1)) { - /* Found out about the first uncorrectable error */ - /* Read the error location */ + // Found out about the first uncorrectable error + // Read the error location pci_conf_read(0, 24, 3, 0x50, 4, &mcanb_add); - /* Parse the error location */ + // Parse the error location page = (mcanb_add >> 12); offset = (mcanb_add >> 3) & 0xFFF; - /* Report the error */ + // Report the error print_ecc_err(page, offset, 0, 0, 0); - /* Clear the error registers */ + // Clear the error registers pci_conf_write(0, 24, 3, 0x4C, 4, mcanb & 0x7FFFFFF ); } } +*/ static void setup_amd751(void) { @@ -436,6 +513,7 @@ static void setup_amd751(void) ctrl.mode = (dram_status & (1 << 2))?ECC_CORRECT: ECC_NONE; } +/* static void poll_amd751(void) { unsigned long ecc_status; @@ -445,34 +523,34 @@ static void poll_amd751(void) int bits; int i; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 2, &ecc_status); if (ecc_status & (3 << 8)) { for(i = 0; i < 6; i++) { if (!(ecc_status & (1 << i))) { continue; } - /* Find the bank the error occured on */ + // Find the bank the error occured on bank_addr = 0x40 + (i << 1); - /* Now get the information on the erroring bank */ + // Now get the information on the erroring bank pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, bank_addr, 2, &bank_info); - /* Parse the error location and error type */ + // Parse the error location and error type page = (bank_info & 0xFF80) << 4; bits = (((ecc_status >> 8) &3) == 2)?1:2; - /* Report the error */ + // Report the error print_ecc_err(page, 0, bits==1?1:0, 0, 0); } - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 2, 0); } } -/* Still waiting for the CORRECT intel datasheet +// Still waiting for the CORRECT intel datasheet static void setup_i85x(void) { unsigned long drc; @@ -495,6 +573,7 @@ static void setup_amd76x(void) ctrl.mode = ddim[(ecc_mode_status >> 10)&3]; } +/* static void poll_amd76x(void) { unsigned long ecc_mode_status; @@ -502,43 +581,44 @@ static void poll_amd76x(void) unsigned long bank_info; unsigned long page; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x48, 4, &ecc_mode_status); - /* Multibit error */ + // Multibit error if (ecc_mode_status & (1 << 9)) { - /* Find the bank the error occured on */ + // Find the bank the error occured on bank_addr = 0xC0 + (((ecc_mode_status >> 4) & 0xf) << 2); - /* Now get the information on the erroring bank */ + // Now get the information on the erroring bank pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, bank_addr, 4, &bank_info); - /* Parse the error location and error type */ + // Parse the error location and error type page = (bank_info & 0xFF800000) >> 12; - /* Report the error */ + // Report the error print_ecc_err(page, 0, 1, 0, 0); } - /* Singlebit error */ + // Singlebit error if (ecc_mode_status & (1 << 8)) { - /* Find the bank the error occured on */ + // Find the bank the error occured on bank_addr = 0xC0 + (((ecc_mode_status >> 0) & 0xf) << 2); - /* Now get the information on the erroring bank */ + // Now get the information on the erroring bank pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, bank_addr, 4, &bank_info); - /* Parse the error location and error type */ + // Parse the error location and error type page = (bank_info & 0xFF800000) >> 12; - /* Report the error */ + // Report the error print_ecc_err(page, 0, 0, 0, 0); } - /* Clear the error status */ + // Clear the error status if (ecc_mode_status & (3 << 8)) { pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0x48, 4, ecc_mode_status); } } +*/ static void setup_cnb20(void) { @@ -658,8 +738,10 @@ static void setup_iE7520(void) /* Clear any prexisting error reports */ pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 2, 0x4747); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 2, 0x4747); + } +/* static void poll_iE7xxx(void) { unsigned long ferr; @@ -669,50 +751,51 @@ static void poll_iE7xxx(void) pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 1, &nerr); if (ferr & 1) { - /* Find out about the first correctable error */ + // Find out about the first correctable error unsigned long celog_add; unsigned long celog_syndrome; unsigned long page; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xA0, 4, &celog_add); - /* Read the syndrome */ + // Read the syndrome pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xD0, 2, &celog_syndrome); - /* Parse the error location */ + // Parse the error location page = (celog_add & 0x0FFFFFC0) >> 6; - /* Report the error */ + // Report the error print_ecc_err(page, 0, 1, celog_syndrome, 0); - /* Clear Bit */ + // Clear Bit pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 1, ferr & 3); } if (ferr & 2) { - /* Found out about the first uncorrectable error */ + // Found out about the first uncorrectable error unsigned long uccelog_add; unsigned long page; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xB0, 4, &uccelog_add); - /* Parse the error location */ + // Parse the error location page = (uccelog_add & 0x0FFFFFC0) >> 6; - /* Report the error */ + // Report the error print_ecc_err(page, 0, 0, 0, 0); - /* Clear Bit */ + // Clear Bit pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 1, ferr & 3); } - /* Check if DRAM_NERR contains data */ + // Check if DRAM_NERR contains data if (nerr & 3) { pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 1, nerr & 3); } } +*/ static void setup_i440gx(void) { @@ -725,19 +808,20 @@ static void setup_i440gx(void) ctrl.mode = ddim[(nbxcfg >> 7)&3]; } +/* static void poll_i440gx(void) { unsigned long errsts; unsigned long page; int bits; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x91, 2, &errsts); if (errsts & 0x11) { unsigned long eap; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x80, 4, &eap); - /* Parse the error location and error type */ + // Parse the error location and error type page = (eap & 0xFFFFF000) >> 12; bits = 0; if (eap &3) { @@ -745,16 +829,19 @@ static void poll_i440gx(void) } if (bits) { - /* Report the error */ + // Report the error print_ecc_err(page, 0, bits==1?1:0, 0, 0); } - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0x91, 2, 0x11); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0x80, 4, 3); } } +*/ + + static void setup_i840(void) { static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_CORRECT }; @@ -766,6 +853,7 @@ static void setup_i840(void) ctrl.mode = ddim[(mchcfg >> 7)&3]; } +/* static void poll_i840(void) { unsigned long errsts; @@ -773,29 +861,32 @@ static void poll_i840(void) unsigned long syndrome; int channel; int bits; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); if (errsts & 3) { unsigned long eap; unsigned long derrctl_sts; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE4, 4, &eap); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, &derrctl_sts); - /* Parse the error location and error type */ + // Parse the error location and error type page = (eap & 0xFFFFF800) >> 11; channel = eap & 1; syndrome = derrctl_sts & 0xFF; bits = ((errsts & 3) == 1)?1:2; - /* Report the error */ + // Report the error print_ecc_err(page, 0, bits==1?1:0, syndrome, channel); - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, 3 << 10); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 3); } } +*/ + + static void setup_i875(void) { @@ -883,8 +974,27 @@ static void setup_p35(void) ctrl.mode = ECC_NONE; + /* + ulong toto; + pci_conf_write(0, 31, 3, 0x40, 1, 0x1); + pci_conf_read(0, 31, 3, 0x0, 4, &toto); + hprint(11,0,toto); + pci_conf_read(0, 31, 3, 0x10, 4, &toto); + hprint(11,10,toto) ; + pci_conf_read(0, 31, 3, 0x20, 4, &toto); + hprint(11,20,toto) ; + pci_conf_read(0, 28, 0, 0x0, 4, &toto); + hprint(11,30,toto); + pci_conf_read(0, 31, 0, 0x0, 4, &toto); + hprint(11,40,toto) ; + pci_conf_read(0, 31, 1, 0x0, 4, &toto); + hprint(11,50,toto) ; + pci_conf_read(0, 31, 2, 0x0, 4, &toto); + hprint(11,60,toto) ; + */ } +/* static void poll_i875(void) { unsigned long errsts; @@ -893,117 +1003,125 @@ static void poll_i875(void) unsigned long syndrome; int channel; int bits; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); if (errsts & 0x81) { unsigned long eap; unsigned long derrsyn; - /* Read the error location, syndrome and channel */ + // Read the error location, syndrome and channel pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 4, &eap); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x5C, 1, &derrsyn); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x5D, 1, &des); - /* Parse the error location and error type */ + // Parse the error location and error type page = (eap & 0xFFFFF000) >> 12; syndrome = derrsyn; channel = des & 1; bits = (errsts & 0x80)?0:1; - /* Report the error */ + // Report the error print_ecc_err(page, 0, bits, syndrome, channel); - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 0x81); } } +*/ static void setup_i845(void) { static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED }; unsigned long drc; - /* Fill in the correct memory capabilites */ + // Fill in the correct memory capabilites pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x7C, 4, &drc); ctrl.cap = ECC_CORRECT; ctrl.mode = ddim[(drc >> 20)&3]; } +/* static void poll_i845(void) { unsigned long errsts; unsigned long page, offset; unsigned long syndrome; int bits; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); if (errsts & 3) { unsigned long eap; unsigned long derrsyn; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x8C, 4, &eap); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x86, 1, &derrsyn); - /* Parse the error location and error type */ + // Parse the error location and error type offset = (eap & 0xFE) << 4; page = (eap & 0x3FFFFFFE) >> 8; syndrome = derrsyn; bits = ((errsts & 3) == 1)?1:2; - /* Report the error */ + // Report the error print_ecc_err(page, offset, bits==1?1:0, syndrome, 0); - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 3); } } +*/ + + static void setup_i820(void) { static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_CORRECT }; unsigned long mchcfg; - /* Fill in the correct memory capabilites */ + // Fill in the correct memory capabilites pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xbe, 2, &mchcfg); ctrl.cap = ECC_CORRECT; ctrl.mode = ddim[(mchcfg >> 7)&3]; } +/* static void poll_i820(void) { unsigned long errsts; unsigned long page; unsigned long syndrome; int bits; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); if (errsts & 3) { unsigned long eap; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xc4, 4, &eap); - /* Parse the error location and error type */ + // Parse the error location and error type page = (eap & 0xFFFFF000) >> 4; syndrome = eap & 0xFF; bits = ((errsts & 3) == 1)?1:2; - /* Report the error */ + // Report the error print_ecc_err(page, 0, bits==1?1:0, syndrome, 0); - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 3); } } +*/ static void setup_i850(void) { static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED }; unsigned long mchcfg; - /* Fill in the correct memory capabilites */ + // Fill in the correct memory capabilites pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x50, 2, &mchcfg); ctrl.cap = ECC_CORRECT; ctrl.mode = ddim[(mchcfg >> 7)&3]; } +/* static void poll_i850(void) { unsigned long errsts; @@ -1011,28 +1129,29 @@ static void poll_i850(void) unsigned long syndrome; int channel; int bits; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); if (errsts & 3) { unsigned long eap; unsigned long derrctl_sts; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE4, 4, &eap); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, &derrctl_sts); - /* Parse the error location and error type */ + // Parse the error location and error type page = (eap & 0xFFFFF800) >> 11; channel = eap & 1; syndrome = derrctl_sts & 0xFF; bits = ((errsts & 3) == 1)?1:2; - /* Report the error */ + // Report the error print_ecc_err(page, 0, bits==1?1:0, syndrome, channel); - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); } } +*/ static void setup_i860(void) { @@ -1040,16 +1159,17 @@ static void setup_i860(void) unsigned long mchcfg; unsigned long errsts; - /* Fill in the correct memory capabilites */ + // Fill in the correct memory capabilites pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x50, 2, &mchcfg); ctrl.cap = ECC_CORRECT; ctrl.mode = ddim[(mchcfg >> 7)&3]; - /* Clear any prexisting error reports */ + // Clear any prexisting error reports pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); } +/* static void poll_i860(void) { unsigned long errsts; @@ -1057,29 +1177,30 @@ static void poll_i860(void) unsigned char syndrome; int channel; int bits; - /* Read the error status */ + // Read the error status pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); if (errsts & 3) { unsigned long eap; unsigned long derrctl_sts; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE4, 4, &eap); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, &derrctl_sts); - /* Parse the error location and error type */ + // Parse the error location and error type page = (eap & 0xFFFFFE00) >> 9; channel = eap & 1; syndrome = derrctl_sts & 0xFF; bits = ((errsts & 3) == 1)?1:2; - /* Report the error */ + // Report the error print_ecc_err(page, 0, bits==1?1:0, syndrome, channel); - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); } } + static void poll_iE7221(void) { unsigned long errsts; @@ -1097,11 +1218,11 @@ static void poll_iE7221(void) unsigned long eap, offset; unsigned long derrctl_sts; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 4, &eap); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x5C, 1, &derrctl_sts); - /* Parse the error location and error type */ + // Parse the error location and error type channel = eap & 1; eap = eap & 0xFFFFFF80; page = eap >> 12; @@ -1109,10 +1230,10 @@ static void poll_iE7221(void) syndrome = derrctl_sts & 0xFF; bits = errocc & 1; - /* Report the error */ + // Report the error print_ecc_err(page, offset, bits, syndrome, channel); - /* Clear the error status */ + // Clear the error status pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); } @@ -1123,6 +1244,7 @@ static void poll_iE7221(void) } } + static void poll_iE7520(void) { unsigned long ferr; @@ -1132,54 +1254,54 @@ static void poll_iE7520(void) pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 2, &nerr); if (ferr & 0x0101) { - /* Find out about the first correctable error */ + // Find out about the first correctable error unsigned long celog_add; unsigned long celog_syndrome; unsigned long page; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xA0, 4,&celog_add); - /* Read the syndrome */ + // Read the syndrome pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xC4, 2, &celog_syndrome); - /* Parse the error location */ + // Parse the error location page = (celog_add & 0x7FFFFFFC) >> 2; - /* Report the error */ + // Report the error print_ecc_err(page, 0, 1, celog_syndrome, 0); - /* Clear Bit */ + // Clear Bit pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 2, ferr& 0x0101); } if (ferr & 0x4646) { - /* Found out about the first uncorrectable error */ + // Found out about the first uncorrectable error unsigned long uccelog_add; unsigned long page; - /* Read the error location */ + // Read the error location pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xA4, 4, &uccelog_add); - /* Parse the error location */ + // Parse the error location page = (uccelog_add & 0x7FFFFFFC) >> 2; - /* Report the error */ + // Report the error print_ecc_err(page, 0, 0, 0, 0); - /* Clear Bit */ + // Clear Bit pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 2, ferr & 0x4646); } - /* Check if DRAM_NERR contains data */ + // Check if DRAM_NERR contains data if (nerr & 0x4747) { pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 2, nerr & 0x4747); } } +*/ - -/* ------------------ Here the code for FSB detection ------------------ */ +/* ----------------- Here's the code for FSB detection ----------------- */ /* --------------------------------------------------------------------- */ static float athloncoef[] = {11, 11.5, 12.0, 12.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5}; @@ -1188,15 +1310,25 @@ static float p4model1ratios[] = {16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 1 static float getP4PMmultiplier(void) { - unsigned int msr_lo, msr_hi; + //unsigned int msr_lo, msr_hi; + int msr_lo, msr_hi; float coef; - /* Find multiplier (by MSR) */ - if (cpu_id.type == 6) { - if((cpu_id.feature_flag >> 7) & 1) { + + /* Find multiplier (by MSR) */ + if (cpu_id.vers.bits.family == 6) + { + if(cpu_id.fid.bits.eist & 1) + { rdmsr(0x198, msr_lo, msr_hi); - coef = ((msr_lo >> 8) & 0x1F); - if ((msr_lo >> 14) & 0x1) { coef = coef + 0.5f; } + coef = ((msr_lo) >> 8) & 0x1F; + if ((msr_lo >> 14) & 0x1) { coef += 0.5f; } + // Atom Fix + if(coef == 6) + { + coef = ((msr_hi) >> 8) & 0x1F; + if ((msr_hi >> 14) & 0x1) { coef += 0.5f; } + } } else { rdmsr(0x2A, msr_lo, msr_hi); coef = (msr_lo >> 22) & 0x1F; @@ -1204,7 +1336,7 @@ static float getP4PMmultiplier(void) } else { - if (cpu_id.model < 2) + if (cpu_id.vers.bits.model < 2) { rdmsr(0x2A, msr_lo, msr_hi); coef = (msr_lo >> 8) & 0xF; @@ -1216,6 +1348,7 @@ static float getP4PMmultiplier(void) coef = (msr_lo >> 24) & 0x1F; } } + return coef; } @@ -1236,75 +1369,51 @@ static float getNHMmultiplier(void) return coef; } - static float getSNBmultiplier(void) { unsigned int msr_lo, msr_hi; float coef; - rdmsr(0x198, msr_lo, msr_hi); - coef = (msr_lo >> 8) & 0xFF; - if(coef < 4) - { - rdmsr(0xCE, msr_lo, msr_hi); - coef = (msr_lo >> 16) & 0xFF; - } - - + rdmsr(0xCE, msr_lo, msr_hi); + coef = (msr_lo >> 8) & 0xFF; return coef; } - -void getIntelPNS(void) +static void poll_fsb_ct(void) { - int i,j; - long psn_eax, psn_ebx, psn_ecx, psn_edx; - long char_hex; - long ocpuid = 0x80000002; - - for(j = 0; j < 4; j++) - { - - asm __volatile__( - "pushl %%ebx\n\t" \ - "cpuid\n\t" \ - "movl %%ebx, %1\n\t" \ - "popl %%ebx\n\t" \ - : "=a" (psn_eax), "=r" (psn_ebx), "=c" (psn_ecx), "=d" (psn_edx) - : "a" (ocpuid) - : "cc" - ); - + unsigned long mcr, mdr; + double dramratio, dramclock, fsb; + float coef = getP4PMmultiplier(); - for(i = 0; i < 4; i++) - { - char_hex = (psn_eax >> (i*8)) & 0xff; - cprint(LINE_CPU+5, col + i, convert_hex_to_char(char_hex)); + /* Build the MCR Message*/ + mcr = (0x10 << 24); // 10h = Read - 11h = Write + mcr += (0x01 << 16); // DRAM Registers located on port 01h + mcr += (0x01 << 8); // DRP = 00h, DTR0 = 01h, DTR1 = 02h, DTR2 = 03h + mcr &= 0xFFFFFFF0; // bit 03:00 RSVD - char_hex = (psn_ebx >> (i*8)) & 0xff; - cprint(LINE_CPU+5, col + i + 4, convert_hex_to_char(char_hex)); - - if(psn_ecx != 0x20202020) - { - char_hex = (psn_ecx >> (i*8)) & 0xff; - cprint(LINE_CPU+5, col + i + 8, convert_hex_to_char(char_hex)); - - char_hex = (psn_edx >> (i*8)) & 0xff; - cprint(LINE_CPU+5, col + i + 12, convert_hex_to_char(char_hex)); - } - else - { - char_hex = (psn_edx >> (i*8)) & 0xff; - cprint(LINE_CPU+5, col + i + 8, convert_hex_to_char(char_hex)); - } - } - (psn_ecx != 0x20202020)?(col += 16):(col +=12); - if(psn_edx == 0x20202020) { col -= 4; } - ocpuid++; - } + /* Send Message to GMCH */ + pci_conf_write(0, 0, 0, 0xD0, 4, mcr); + + /* Read Answer from Sideband bus */ + pci_conf_read(0, 0, 0, 0xD4, 4, &mdr); - col -= 16; + /* Get RAM ratio */ + switch (mdr & 0x3) { + default: + case 0: dramratio = 3.0f; break; + case 1: dramratio = 4.0f; break; + case 2: dramratio = 5.0f; break; + case 3: dramratio = 6.0f; break; + } + + // Compute FSB & RAM Frequency + fsb = ((extclock / 1000) / coef); + dramclock = fsb * dramratio; + + // Print'em all. Whoa ! + print_cpu_line(dramclock, fsb, 3); + } static void poll_fsb_amd64(void) { @@ -1315,12 +1424,16 @@ static void poll_fsb_amd64(void) { unsigned long dramchr; float clockratio; double dramclock; + unsigned int dummy[3]; + int ram_type; float coef = 10; + cpuid(0x80000007, &dummy[0], &dummy[1], &dummy[2], &dummy[3]); + /* First, got the FID by MSR */ /* First look if Cool 'n Quiet is supported to choose the best msr */ - if (((cpu_id.pwrcap >> 1) & 1) == 1) { + if (((dummy[3] >> 1) & 1) == 1) { rdmsr(0xc0010042, mcgsrl, mcgsth); fid = (mcgsrl & 0x3F); } else { @@ -1335,12 +1448,12 @@ static void poll_fsb_amd64(void) { if (fid & 1) { coef = coef + 0.5; } /* Next, we need the clock ratio */ - - if (((cpu_id.ext >> 16) & 0xF) >= 4) { + if (cpu_id.vers.bits.extendedModel >= 4) { /* K8 0FH */ pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); temp2 = (dramchr & 0x7); clockratio = coef; + ram_type = 2; switch (temp2) { case 0x0: @@ -1361,6 +1474,7 @@ static void poll_fsb_amd64(void) { /* OLD K8 */ pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); temp2 = (dramchr >> 20) & 0x7; + ram_type = 1; clockratio = coef; switch (temp2) { @@ -1386,10 +1500,10 @@ static void poll_fsb_amd64(void) { } /* Compute the final DRAM Clock */ - dramclock = (extclock /1000) / clockratio; + dramclock = (extclock / 1000) / clockratio; /* ...and print */ - print_fsb_info(dramclock, "RAM : ", "DDR"); + print_cpu_line(dramclock, (extclock / 1000 / coef), ram_type); } @@ -1401,30 +1515,9 @@ static void poll_fsb_k10(void) { unsigned long dramchr; unsigned long mainPllId; double dramclock; - unsigned long pns_low; - unsigned long pns_high; - unsigned long msr_psn; - - - /* If ECC not enabled : display CPU name as IMC */ - if(ctrl.mode == ECC_NONE) - { - cprint(LINE_CPU+5, 0, "IMC : "); - for(msr_psn = 0; msr_psn < 5; msr_psn++) - { - rdmsr(0xC0010030+msr_psn, pns_low, pns_high); - cprint(LINE_CPU+5, 6+(msr_psn*8), convert_hex_to_char(pns_low & 0xff)); - cprint(LINE_CPU+5, 7+(msr_psn*8), convert_hex_to_char((pns_low >> 8) & 0xff)); - cprint(LINE_CPU+5, 8+(msr_psn*8), convert_hex_to_char((pns_low >> 16) & 0xff)); - cprint(LINE_CPU+5, 9+(msr_psn*8), convert_hex_to_char((pns_low >> 24) & 0xff)); - cprint(LINE_CPU+5, 10+(msr_psn*8), convert_hex_to_char(pns_high & 0xff)); - cprint(LINE_CPU+5, 11+(msr_psn*8), convert_hex_to_char((pns_high >> 8) & 0xff)); - cprint(LINE_CPU+5, 12+(msr_psn*8), convert_hex_to_char((pns_high >> 16) & 0xff)); - cprint(LINE_CPU+5, 13+(msr_psn*8), convert_hex_to_char((pns_high >> 24) & 0xff)); - } - cprint(LINE_CPU+5, 41, "(ECC : Disabled)"); - } - + ulong offset = 0; + int ram_type = 2; + /* First, we need the clock ratio */ pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); temp2 = (dramchr & 0x7); @@ -1437,16 +1530,14 @@ static void poll_fsb_k10(void) { default: temp2 += 3; } - /* Compute the final DRAM Clock */ - if (((cpu_id.ext >> 20) & 0xFF) == 1) + if (((cpu_id.vers.bits.extendedModel >> 4) & 0xFF) == 1) { dramclock = ((temp2 * 200) / 3.0) + 0.25; - else { + } else { unsigned long target; unsigned long dx; unsigned divisor; - target = temp2 * 400; /* Get the FID by MSR */ @@ -1470,75 +1561,262 @@ static void poll_fsb_k10(void) { if ( (dx / divisor) <= target ) break; + + pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); + + // If Channel A not enabled, switch to channel B + if(((dramchr>>14) & 0x1)) + { + offset = 0x100; + pci_conf_read(0, 24, 2, 0x94+offset, 4, &dramchr); + } + + //DDR2 or DDR3 + if ((dramchr >> 8)&1) { + ram_type = 3; + } else { + ram_type = 2;; + } + dramclock = ((dx / divisor) / 6.0) + 0.25; -/* - * dramclock = ((((dx * extclock) / divisor) / (mainPllId+8)) / 600000.0) + 0.25; - */ } /* ...and print */ - print_fsb_info(dramclock, "RAM : ", "DDR"); + print_cpu_line(dramclock, 0, ram_type); } -static void poll_fsb_k14(void) { +static void poll_fsb_k12(void) { unsigned long temp2; unsigned long dramchr; - double dramclock; - unsigned long pns_low; - unsigned long pns_high; - unsigned long msr_psn; + double dramratio, dramclock, fsb, did; + unsigned int mcgsrl,mcgsth, fid, did_raw; + + // Get current FID & DID + rdmsr(0xc0010071, mcgsrl, mcgsth); + did_raw = mcgsrl & 0xF; + fid = (mcgsrl >> 4) & 0xF; + + switch(did_raw) + { + default: + case 0x0: + did = 1.0f; + break; + case 0x1: + did = 1.5f; + break; + case 0x2: + did = 2.0f; + break; + case 0x3: + did = 3.0f; + break; + case 0x4: + did = 4.0f; + break; + case 0x5: + did = 6.0f; + break; + case 0x6: + did = 8.0f; + break; + case 0x7: + did = 12.0f; + break; + case 0x8: + did = 16.0f; + break; + } + + fsb = ((extclock / 1000.0f) / ((fid + 16.0f) / did)); + + /* Finaly, we need the clock ratio */ + pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); + + if(((dramchr >> 14) & 0x1) == 1) + { + pci_conf_read(0, 24, 2, 0x194, 4, &dramchr); + } + + temp2 = (dramchr & 0x1F); + switch (temp2) { + default: + case 0x06: + dramratio = 4.0f; + break; + case 0x0A: + dramratio = 16.0f / 3.0f; + break; + case 0x0E: + dramratio = 20.0f / 3.0f; + break; + case 0x12: + dramratio = 8.0f; + break; + case 0x16: + dramratio = 28.0f / 3.0f; + break; + } + + dramclock = fsb * dramratio; + + /* print */ + print_cpu_line(dramclock, fsb, 3); - /* If ECC not enabled : display CPU name as IMC */ - if(ctrl.mode == ECC_NONE) - { - cprint(LINE_CPU+5, 0, "IMC : "); - for(msr_psn = 0; msr_psn < 5; msr_psn++) - { - rdmsr(0xC0010030+msr_psn, pns_low, pns_high); - cprint(LINE_CPU+5, 6+(msr_psn*8), convert_hex_to_char(pns_low & 0xff)); - cprint(LINE_CPU+5, 7+(msr_psn*8), convert_hex_to_char((pns_low >> 8) & 0xff)); - cprint(LINE_CPU+5, 8+(msr_psn*8), convert_hex_to_char((pns_low >> 16) & 0xff)); - cprint(LINE_CPU+5, 9+(msr_psn*8), convert_hex_to_char((pns_low >> 24) & 0xff)); - cprint(LINE_CPU+5, 10+(msr_psn*8), convert_hex_to_char(pns_high & 0xff)); - cprint(LINE_CPU+5, 11+(msr_psn*8), convert_hex_to_char((pns_high >> 8) & 0xff)); - cprint(LINE_CPU+5, 12+(msr_psn*8), convert_hex_to_char((pns_high >> 16) & 0xff)); - cprint(LINE_CPU+5, 13+(msr_psn*8), convert_hex_to_char((pns_high >> 24) & 0xff)); - } - cprint(LINE_CPU+5, 41, "(ECC : Disabled)"); - } +} - /* First, we need the clock ratio */ - pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); - temp2 = (dramchr & 0x1F); +static void poll_fsb_k16(void) +{ - switch (temp2) { - default: - case 6: - dramclock = 400; - break; - case 10: - dramclock = 533; - break; - case 14: - dramclock = 667; - break; - } + unsigned long dramchr; + double dramratio, dramclock, fsb; + + // FIXME: Unable to find a real way to detect multiplier. + fsb = 100.0f; + + /* Clock ratio */ + pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); + + switch (dramchr & 0x1F) { + default: + case 0x04: /* 333 */ + dramratio = 10.0f / 3.0f; + break; + case 0x06: /* 400 */ + dramratio = 4.0f; + break; + case 0x0A: /* 533 */ + dramratio = 16.0f / 3.0f; + break; + case 0x0E: /* 667 */ + dramratio = 20.0f / 3.0f; + break; + case 0x12: /* 800 */ + dramratio = 8.0f; + break; + case 0x16: /* 933 */ + dramratio = 28.0f / 3.0f; + break; + case 0x19: /* 1050 */ + dramratio = 21.0f / 2.0f; + break; + case 0x1A: /* 1066 */ + dramratio = 32.0f / 3.0f; + break; + } + + dramclock = fsb * dramratio; + + /* print */ + print_cpu_line(dramclock, fsb, 3); + +} + +static void poll_fsb_k15(void) { + + unsigned long temp2; + unsigned long dramchr; + double dramratio, dramclock, fsb; + unsigned int mcgsrl,mcgsth, fid, did; + + // Get current FID & DID + rdmsr(0xc0010071, mcgsrl, mcgsth); + fid = mcgsrl & 0x3F; + did = (mcgsrl >> 6) & 0x7; + + fsb = ((extclock / 1000.0f) / ((fid + 16.0f) / (2^did)) / 2); + + /* Finaly, we need the clock ratio */ + pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); + + if(((dramchr >> 14) & 0x1) == 1) + { + pci_conf_read(0, 24, 2, 0x194, 4, &dramchr); + } + + temp2 = (dramchr & 0x1F); + + switch (temp2) { + case 0x04: + dramratio = 10.0f / 3.0f; + break; + default: + case 0x06: + dramratio = 4.0f; + break; + case 0x0A: + dramratio = 16.0f / 3.0f; + break; + case 0x0E: + dramratio = 20.0f / 3.0f; + break; + case 0x12: + dramratio = 8.0f; + break; + case 0x16: + dramratio = 28.0f / 3.0f; + break; + case 0x1A: + dramratio = 32.0f / 3.0f; + break; + case 0x1F: + dramratio = 36.0f / 3.0f; + break; + } + + dramclock = fsb * dramratio; + + /* print */ + print_cpu_line(dramclock, fsb, 3); + +} +static void poll_fsb_k14(void) +{ + + unsigned long dramchr; + double dramratio, dramclock, fsb; + // FIXME: Unable to find a real way to detect multiplier. + fsb = 100.0f; + + /* Clock ratio */ + pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); + + switch (dramchr & 0x1F) { + default: + case 0x06: + dramratio = 4.0f; + break; + case 0x0A: + dramratio = 16.0f / 3.0f; + break; + case 0x0E: + dramratio = 20.0f / 3.0f; + break; + case 0x12: + dramratio = 8.0f; + break; + } + + dramclock = fsb * dramratio; + /* print */ - print_fsb_info(dramclock, "RAM : ", "DDR-"); + print_cpu_line(dramclock, fsb, 3); } + static void poll_fsb_i925(void) { double dramclock, dramratio, fsb; unsigned long mchcfg, mchcfg2, dev0, drc, idetect; float coef = getP4PMmultiplier(); long *ptr; + int ddr_type; pci_conf_read( 0, 0, 0, 0x02, 2, &idetect); @@ -1556,8 +1834,10 @@ static void poll_fsb_i925(void) { if ((drc&3) != 2) { // We are in DDR1 Mode if (mchcfg2 == 1) { dramratio = 0.8; } else { dramratio = 1; } + ddr_type = 1; } else { // We are in DDR2 Mode + ddr_type = 2; if ((mchcfg >> 2)&1) { // We are in FSB1066 Mode if (mchcfg2 == 2) { dramratio = 0.75; } else { dramratio = 1; } @@ -1581,16 +1861,8 @@ static void poll_fsb_i925(void) { fsb = ((extclock / 1000) / coef); dramclock = fsb * dramratio; - // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR"); - /* Print FSB (only if ECC is not enabled) */ - cprint(LINE_CPU+5, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; + print_cpu_line(dramclock, fsb, ddr_type); } @@ -1617,21 +1889,72 @@ static void poll_fsb_i945(void) { // Compute RAM Frequency fsb = ((extclock / 1000) / coef); + dramclock = fsb * dramratio; - // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR"); + // Print + print_cpu_line(dramclock, fsb, 2); - /* Print FSB (only if ECC is not enabled) */ - cprint(LINE_CPU+5, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; +} + +static void poll_fsb_i945gme(void) { + + double dramclock, dramratio, fsb; + unsigned long mchcfg, dev0, fsb_mch; + float coef = getP4PMmultiplier(); + long *ptr; + + /* Find dramratio */ + pci_conf_read( 0, 0, 0, 0x44, 4, &dev0); + dev0 &= 0xFFFFC000; + ptr=(long*)(dev0+0xC00); + mchcfg = *ptr & 0xFFFF; + dramratio = 1; + + switch (mchcfg & 7) { + case 0: fsb_mch = 400; break; + default: + case 1: fsb_mch = 533; break; + case 2: fsb_mch = 667; break; + } + + + switch (fsb_mch) { + case 400: + switch ((mchcfg >> 4)&7) { + case 2: dramratio = 1.0f; break; + case 3: dramratio = 4.0f/3.0f; break; + case 4: dramratio = 5.0f/3.0f; break; + } + break; + + default: + case 533: + switch ((mchcfg >> 4)&7) { + case 2: dramratio = 3.0f/4.0f; break; + case 3: dramratio = 1.0f; break; + case 4: dramratio = 5.0f/4.0f; break; + } + break; + + case 667: + switch ((mchcfg >> 4)&7) { + case 2: dramratio = 3.0f/5.0f; break; + case 3: dramratio = 4.0f/5.0f; break; + case 4: dramratio = 1.0f; break; + } + break; + } + + // Compute RAM Frequency + fsb = ((extclock / 1000) / coef); + dramclock = fsb * dramratio * 2; + + print_cpu_line(dramclock, fsb, 2); } + static void poll_fsb_i975(void) { double dramclock, dramratio, fsb; @@ -1681,23 +2004,13 @@ static void poll_fsb_i975(void) { case 4: dramratio = 1.5; break; } break; -} - + } // Compute RAM Frequency fsb = ((extclock / 1000) / coef); dramclock = fsb * dramratio; - // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR"); - - /* Print FSB (only if ECC is not enabled) */ - cprint(LINE_CPU+5, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; + print_cpu_line(dramclock, fsb, 2); } @@ -1740,7 +2053,7 @@ static void poll_fsb_i965(void) { case 0: dramratio = 1.0; break; case 1: dramratio = 5.0f/4.0f; break; case 2: dramratio = 5.0f/3.0f; break; - case 3: dramratio = 2.0; break; + case 3: dramratio = 2.0f; break; case 4: dramratio = 8.0f/3.0f; break; case 5: dramratio = 10.0f/3.0f; break; } @@ -1781,15 +2094,127 @@ static void poll_fsb_i965(void) { dramclock = fsb * dramratio; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR"); + print_cpu_line(dramclock, fsb, 2); - /* Print FSB (only if ECC is not enabled) */ - cprint(LINE_CPU+5, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; +} + +static void poll_fsb_p35(void) { + + double dramclock, dramratio, fsb; + unsigned long mchcfg, dev0, fsb_mch, Device_ID, Memory_Check, c0ckectrl, offset; + float coef = getP4PMmultiplier(); + long *ptr; + int ram_type; + + pci_conf_read( 0, 0, 0, 0x02, 2, &Device_ID); + Device_ID &= 0xFFFF; + + /* Find dramratio */ + pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); + dev0 &= 0xFFFFC000; + + ptr = (long*)(dev0+0x260); + c0ckectrl = *ptr & 0xFFFFFFFF; + + + // If DIMM 0 not populated, check DIMM 1 + ((c0ckectrl) >> 20 & 0xF)?(offset = 0):(offset = 0x400); + + ptr=(long*)(dev0+0xC00); + mchcfg = *ptr & 0xFFFF; + dramratio = 1; + + switch (mchcfg & 7) { + case 0: fsb_mch = 1066; break; + case 1: fsb_mch = 533; break; + default: case 2: fsb_mch = 800; break; + case 3: fsb_mch = 667; break; + case 4: fsb_mch = 1333; break; + case 6: fsb_mch = 1600; break; + } + + + switch (fsb_mch) { + case 533: + switch ((mchcfg >> 4)&7) { + case 1: dramratio = 2.0; break; + case 2: dramratio = 2.5; break; + case 3: dramratio = 3.0; break; + } + break; + + default: + case 800: + switch ((mchcfg >> 4)&7) { + case 0: dramratio = 1.0; break; + case 1: dramratio = 5.0f/4.0f; break; + case 2: dramratio = 5.0f/3.0f; break; + case 3: dramratio = 2.0; break; + case 4: dramratio = 8.0f/3.0f; break; + case 5: dramratio = 10.0f/3.0f; break; + } + break; + + case 1066: + switch ((mchcfg >> 4)&7) { + case 1: dramratio = 1.0f; break; + case 2: dramratio = 5.0f/4.0f; break; + case 3: dramratio = 3.0f/2.0f; break; + case 4: dramratio = 2.0f; break; + case 5: dramratio = 5.0f/2.0f; break; + } + break; + + case 1333: + switch ((mchcfg >> 4)&7) { + case 2: dramratio = 1.0f; break; + case 3: dramratio = 6.0f/5.0f; break; + case 4: dramratio = 8.0f/5.0f; break; + case 5: dramratio = 2.0f; break; + } + break; + + case 1600: + switch ((mchcfg >> 4)&7) { + case 3: dramratio = 1.0f; break; + case 4: dramratio = 4.0f/3.0f; break; + case 5: dramratio = 3.0f/2.0f; break; + case 6: dramratio = 2.0f; break; + } + break; + + } + + // On P45, check 1A8 + if(Device_ID > 0x2E00 && imc_type != 8) { + ptr = (long*)(dev0+offset+0x1A8); + Memory_Check = *ptr & 0xFFFFFFFF; + Memory_Check >>= 2; + Memory_Check &= 1; + Memory_Check = !Memory_Check; + } else if (imc_type == 8) { + ptr = (long*)(dev0+offset+0x224); + Memory_Check = *ptr & 0xFFFFFFFF; + Memory_Check &= 1; + Memory_Check = !Memory_Check; + } else { + ptr = (long*)(dev0+offset+0x1E8); + Memory_Check = *ptr & 0xFFFFFFFF; + } + + //Determine DDR-II or DDR-III + if (Memory_Check & 1) { + ram_type = 2; + } else { + ram_type = 3; + } + + // Compute RAM Frequency + fsb = ((extclock / 1000) / coef); + dramclock = fsb * dramratio; + + // Print DRAM Freq + print_cpu_line(dramclock, fsb, ram_type); } @@ -1856,15 +2281,7 @@ static void poll_fsb_im965(void) { dramclock = fsb * dramratio; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR"); - - /* Print FSB (only if ECC is not enabled) */ - cprint(LINE_CPU+5, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; + print_cpu_line(dramclock, fsb, 2); } @@ -1905,15 +2322,7 @@ static void poll_fsb_5400(void) { dramclock = fsb * dramratio; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR"); - - /* Print FSB (only if ECC is not enabled) */ - cprint(LINE_CPU+5, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; + print_cpu_line(dramclock, fsb, 2); } @@ -1946,16 +2355,8 @@ static void poll_fsb_nf4ie(void) { fsb = ((extclock /1000) / coef); dramclock = fsb * dramratio; - /* Print DRAM Freq */ - print_fsb_info(dramclock, "RAM : ", "DDR"); - - /* Print FSB */ - cprint(LINE_CPU+5, col, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; + // Print DRAM Freq + print_cpu_line(dramclock, fsb, 2); } @@ -1989,38 +2390,45 @@ static void poll_fsb_i875(void) { fsb = ((extclock /1000) / coef); /* Print DRAM Freq */ - print_fsb_info(dramclock, "RAM : ", "DDR"); - - /* Print FSB (only if ECC is not enabled) */ - if ( ctrl.mode == ECC_NONE ) { - cprint(LINE_CPU+5, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; - } + print_cpu_line(dramclock, fsb, 2); } static void poll_fsb_p4(void) { ulong fsb, idetect; float coef = getP4PMmultiplier(); + char *name; + int col,temp; fsb = ((extclock /1000) / coef); - /* Print FSB */ - cprint(LINE_CPU+5, col +1, "/ FSB : "); - col += 9; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; - /* For synchro only chipsets */ pci_conf_read( 0, 0, 0, 0x02, 2, &idetect); - if (idetect == 0x2540 || idetect == 0x254C) { - print_fsb_info(fsb, "RAM : ", "DDR"); + if (idetect == 0x2540 || idetect == 0x254C) + { + print_cpu_line(fsb, fsb, 1); + } else { + /* Print the controller name */ + col = COL_SPEC; + cprint(LINE_CPU, col, "Chipset: "); + col += 9; + /* Print the controller name */ + name = controllers[ctrl.index].name; + cprint(LINE_CPU, col, name); + /* Now figure out how much I just printed */ + temp = 20; + while(name[temp - 20] != '\0') { + col++; + temp++; + } + + if(temp < 36){ + cprint(LINE_CPU, col +1, "- FSB : "); + col += 9; + dprint(LINE_CPU, col, fsb, 3,0); + col += 3; + } + } } @@ -2029,7 +2437,7 @@ static void poll_fsb_i855(void) { double dramclock, dramratio, fsb ; unsigned int msr_lo, msr_hi; - ulong mchcfg, centri, idetect; + ulong mchcfg, idetect; int coef; pci_conf_read( 0, 0, 0, 0x02, 2, &idetect); @@ -2037,33 +2445,16 @@ static void poll_fsb_i855(void) { /* Find multiplier (by MSR) */ /* Is it a Pentium M ? */ - if (cpu_id.type == 6) { + if (cpu_id.vers.bits.family == 6) { rdmsr(0x2A, msr_lo, msr_hi); coef = (msr_lo >> 22) & 0x1F; - - /* Is it an i855GM or PM ? */ - if (idetect == 0x3580) { - cprint(LINE_CPU+5, col-1, "i855GM/GME "); - col += 10; - } } else { rdmsr(0x2C, msr_lo, msr_hi); coef = (msr_lo >> 24) & 0x1F; - cprint(LINE_CPU+5, col-1, "i852PM/GM "); - col += 9; } fsb = ((extclock /1000) / coef); - /* Print FSB */ - cprint(LINE_CPU+5, col, "/ FSB : "); col += 8; - dprint(LINE_CPU+5, col, fsb, 3,0); col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); col += 4; - - /* Is it a Centrino platform or only an i855 platform ? */ - pci_conf_read( 2, 2, 0, 0x02, 2, ¢ri); - if (centri == 0x1043) { cprint(LINE_CPU+5, col +1, "/ Centrino Mobile Platform"); } - else { cprint(LINE_CPU+5, col +1, "/ Mobile Platform"); } /* Compute DRAM Clock */ @@ -2088,7 +2479,7 @@ static void poll_fsb_i855(void) { dramclock = fsb * dramratio; /* ...and print */ - print_fsb_info(dramclock, "RAM : ", "DDR"); + print_cpu_line(dramclock, fsb, 1); } @@ -2099,6 +2490,8 @@ static void poll_fsb_amd32(void) { unsigned long temp; double dramclock; double coef2; + int col; + char *name; /* First, got the FID */ rdmsr(0x0c0010015, mcgsrl, mcgsth); @@ -2112,8 +2505,27 @@ static void poll_fsb_amd32(void) { /* Compute the final FSB Clock */ dramclock = (extclock /1000) / coef2; - /* ...and print */ - print_fsb_info(dramclock, "FSB : ", "DDR"); + /* Print the controller name */ + col = COL_SPEC; + cprint(LINE_CPU, col, "Chipset: "); + col += 9; + /* Print the controller name */ + name = controllers[ctrl.index].name; + cprint(LINE_CPU, col, name); + /* Now figure out how much I just printed */ + temp = 20; + while(name[temp - 20] != '\0') { + col++; + temp++; + } + + if(temp < 36){ + cprint(LINE_CPU, col +1, "- FSB : "); + col += 9; + dprint(LINE_CPU, col, dramclock, 3,0); + col += 3; + } + } @@ -2151,20 +2563,13 @@ static void poll_fsb_nf2(void) { fsb = ((extclock /1000) / coef); /* ...and print */ - - cprint(LINE_CPU+5, col, "/ FSB : "); - col += 8; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - - print_fsb_info(dramclock, "RAM : ", "DDR"); + print_cpu_line(dramclock, fsb, 1); } static void poll_fsb_us15w(void) { - double dramclock, dramratio, fsb, gfx; + double dramclock, dramratio, fsb; unsigned long msr; /* Find dramratio */ @@ -2181,7 +2586,8 @@ static void poll_fsb_us15w(void) { } else { fsb = 400; } - + +/* switch (( msr >> 0 ) & 7) { case 0: gfx = 100; @@ -2205,48 +2611,29 @@ static void poll_fsb_us15w(void) { gfx = 0; break; } + */ dramclock = fsb * dramratio; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR"); - - /* Print FSB (only if ECC is not enabled) */ - cprint(LINE_CPU+4, col +1, "- FSB : "); - col += 9; - dprint(LINE_CPU+4, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+4, col +1, "MHz"); - col += 4; - - cprint(LINE_CPU+4, col +1, "- GFX : "); - col += 9; - dprint(LINE_CPU+4, col, gfx, 3,0); - col += 3; - cprint(LINE_CPU+4, col +1, "MHz"); - col += 4; + print_cpu_line(dramclock, fsb, 1); } static void poll_fsb_nhm(void) { double dramclock, dramratio, fsb; - unsigned long mc_dimm_clk_ratio, qpi_pll_status; + unsigned long mc_dimm_clk_ratio; float coef = getNHMmultiplier(); - float qpi_speed; + //unsigned long qpi_pll_status; + //float qpi_speed; - fsb = ((extclock /1000) / coef); - /* Print FSB */ - cprint(LINE_CPU+5, col +1, "/ BCLK : "); - col += 10; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; + fsb = ((extclock /1000) / coef); /* Print QPI Speed (if ECC not supported) */ - if(ctrl.mode == ECC_NONE && cpu_id.model == 10) { + /* + if(ctrl.mode == ECC_NONE && cpu_id.vers.bits.model == 10) { pci_conf_read(nhm_bus, 2, 1, 0x50, 2, &qpi_pll_status); qpi_speed = (qpi_pll_status & 0x7F) * ((extclock / 1000) / coef) * 2; cprint(LINE_CPU+5, col +1, "/ QPI : "); @@ -2261,6 +2648,7 @@ static void poll_fsb_nhm(void) { cprint(LINE_CPU+5, col +1, "GT/s"); col += 5; } + */ /* Get the clock ratio */ @@ -2272,29 +2660,23 @@ static void poll_fsb_nhm(void) { dramclock = fsb * dramratio / 2; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR3-"); + print_cpu_line(dramclock, fsb, 3); } static void poll_fsb_nhm32(void) { double dramclock, dramratio, fsb; - unsigned long mc_dimm_clk_ratio, qpi_pll_status; + unsigned long mc_dimm_clk_ratio; float coef = getNHMmultiplier(); - float qpi_speed; + //unsigned long qpi_pll_status; + //float qpi_speed; fsb = ((extclock /1000) / coef); - /* Print FSB */ - cprint(LINE_CPU+5, col +1, "/ BCLK : "); - col += 10; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; - /* Print QPI Speed (if ECC not supported) */ - if(ctrl.mode == ECC_NONE && cpu_id.model == 12) { + /* + if(ctrl.mode == ECC_NONE && cpu_id.vers.bits.model == 12) { pci_conf_read(nhm_bus, 2, 1, 0x50, 2, &qpi_pll_status); qpi_speed = (qpi_pll_status & 0x7F) * ((extclock / 1000) / coef) * 2; cprint(LINE_CPU+5, col +1, "/ QPI : "); @@ -2309,6 +2691,7 @@ static void poll_fsb_nhm32(void) { cprint(LINE_CPU+5, col +1, "GT/s"); col += 5; } + */ /* Get the clock ratio */ @@ -2320,41 +2703,23 @@ static void poll_fsb_nhm32(void) { dramclock = fsb * dramratio / 2; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR3-"); + print_cpu_line(dramclock, fsb, 3); } static void poll_fsb_wmr(void) { double dramclock, dramratio, fsb; - unsigned long dev0, mchcfg; + unsigned long dev0; float coef = getNHMmultiplier(); long *ptr; fsb = ((extclock / 1000) / coef); - if(ctrl.mode == ECC_NONE) - { - col = 0; - cprint(LINE_CPU+5, col, "IMC : "); col += 6; - getIntelPNS(); - //cprint(LINE_CPU+5, col, "(ECC : Disabled)"); - //col += 16; - } - - /* Print FSB */ - cprint(LINE_CPU+5, col +1, "/ BCLK : "); - col += 10; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; - /* Find dramratio */ pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); dev0 &= 0xFFFFC000; ptr=(long*)(dev0+0x2C20); - mchcfg = *ptr & 0xFFFF; dramratio = 1; /* Get the clock ratio */ @@ -2364,35 +2729,44 @@ static void poll_fsb_wmr(void) { dramclock = fsb * dramratio; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR3-"); + print_cpu_line(dramclock, fsb, 3); } static void poll_fsb_snb(void) { double dramclock, dramratio, fsb; - unsigned long dev0, mchcfg; + unsigned long dev0; float coef = getSNBmultiplier(); long *ptr; fsb = ((extclock / 1000) / coef); - if(ctrl.mode == ECC_NONE) - { - col = 0; - cprint(LINE_CPU+5, col, "IMC : "); col += 6; - getIntelPNS(); - //cprint(LINE_CPU+5, col, "(ECC : Disabled)"); - //col += 16; - } + /* Find dramratio */ + pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); + dev0 &= 0xFFFFC000; + ptr=(long*)(dev0+0x5E04); + dramratio = 1; + + /* Get the clock ratio */ + dramratio = (float)(*ptr & 0x1F) * (133.34f / 100.0f); + + // Compute RAM Frequency + dramclock = fsb * dramratio; - /* Print FSB */ - cprint(LINE_CPU+5, col +1, "/ BCLK : "); - col += 10; - dprint(LINE_CPU+5, col, fsb, 3,0); - col += 3; - cprint(LINE_CPU+5, col +1, "MHz"); - col += 4; + // Print DRAM Freq + print_cpu_line(dramclock, fsb, 3); + +} + +static void poll_fsb_ivb(void) { + + double dramclock, dramratio, fsb; + unsigned long dev0, mchcfg; + float coef = getSNBmultiplier(); + long *ptr; + + fsb = ((extclock / 1000) / coef); /* Find dramratio */ pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); @@ -2402,13 +2776,47 @@ static void poll_fsb_snb(void) { dramratio = 1; /* Get the clock ratio */ - dramratio = (float)(*ptr & 0x1F) * (133.34f / 100.0f); + switch((mchcfg >> 8) & 0x01) + { + case 0x0: + dramratio = (float)(*ptr & 0x1F) * (133.34f / 100.0f); + break; + case 0x1: + dramratio = (float)(*ptr & 0x1F) * (100.0f / 100.0f); + break; + } + + // Compute RAM Frequency + dramclock = fsb * dramratio; + + // Print DRAM Freq + print_cpu_line(dramclock, fsb, 3); + +} + +static void poll_fsb_snbe(void) { + + double dramclock, dramratio, fsb; + unsigned long dev0; + float coef = getSNBmultiplier(); + + fsb = ((extclock / 1000) / coef); + + /* Find dramratio */ + pci_conf_read( 0xFF, 10, 1, 0x98, 4, &dev0); + dev0 &= 0xFFFFFFFF; + dramratio = 1; + + /* Get the clock ratio */ + dramratio = (float)(dev0 & 0x3F) * (66.67f / 100.0f); // Compute RAM Frequency dramclock = fsb * dramratio; // Print DRAM Freq - print_fsb_info(dramclock, "RAM : ", "DDR3-"); + print_cpu_line(dramclock, fsb, 3); + + } @@ -2419,9 +2827,7 @@ static void poll_timings_nf4ie(void) { ulong regd0, reg8c, reg9c, reg80; - int cas, rcd, rp, ras; - - cprint(LINE_CPU+5, col +1, "- Type : DDR-II"); + int cas, rcd, rp, ras, chan; //Now, read Registers pci_conf_read( 0, 1, 1, 0xD0, 4, ®d0); @@ -2435,14 +2841,12 @@ static void poll_timings_nf4ie(void) { rp = (reg9c >> 8) & 0xF; ras = (reg8c >> 16) & 0x3F; - print_timings_info(cas, rcd, rp, ras); - if (reg80 & 0x3) { - cprint(LINE_CPU+6, col2, "/ Dual Channel (128 bits)"); + chan = 2; } else { - cprint(LINE_CPU+6, col2, "/ Single Channel (64 bits)"); + chan = 1; } - + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_i875(void) { @@ -2450,24 +2854,16 @@ static void poll_timings_i875(void) { ulong dev6, dev62; ulong temp; float cas; - int rcd, rp, ras; + int rcd, rp, ras, chan; long *ptr, *ptr2; - /* Read the MMR Base Address & Define the pointer */ - pci_conf_read( 0, 6, 0, 0x10, 4, &dev6); - - /* Now, the PAT ritual ! (Kant and Luciano will love this) */ pci_conf_read( 0, 6, 0, 0x40, 4, &dev62); ptr2=(long*)(dev6+0x68); - if ((dev62&0x3) == 0 && ((*ptr2 >> 14)&1) == 1) { - cprint(LINE_CPU+5, col +1, "- PAT : Enabled"); - } else { - cprint(LINE_CPU+5, col +1, "- PAT : Disabled"); - } + /* Read the MMR Base Address & Define the pointer */ + pci_conf_read( 0, 6, 0, 0x10, 4, &dev6); /* Now, we could check some additionnals timings infos) */ - ptr=(long*)(dev6+0x60); // CAS Latency (tCAS) temp = ((*ptr >> 5)& 0x3); @@ -2485,20 +2881,20 @@ static void poll_timings_i875(void) { temp = ((*ptr >> 7)& 0x7); ras = 10 - temp; - // Print timings - print_timings_info(cas, rcd, rp, ras); - // Print 64 or 128 bits mode if (((*ptr2 >> 21)&3) > 0) { - cprint(LINE_CPU+6, col2, "/ Dual Channel (128 bits)"); + chan = 2; } else { - cprint(LINE_CPU+6, col2, "/ Single Channel (64 bits)"); + chan = 1; } + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_i925(void) { // Thanks for CDH optis + float cas; + int rcd,rp,ras,chan; ulong dev0, drt, drc, dcc, idetect, temp; long *ptr; @@ -2519,69 +2915,53 @@ static void poll_timings_i925(void) { ptr=(long*)(dev0+0x200); dcc = *ptr & 0xFFFFFFFF; - //Determine DDR or DDR-II - if ((drc & 3) == 2) { - cprint(LINE_CPU+5, col +1, "- Type : DDR2"); - } else { - cprint(LINE_CPU+5, col +1, "- Type : DDR1"); - } - - // Now, detect timings - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; - // CAS Latency (tCAS) temp = ((drt >> 8)& 0x3); if ((drc & 3) == 2){ // Timings DDR-II - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "5-"); } - else if (temp == 0x1) { cprint(LINE_CPU+6, col2, "4-"); } - else if (temp == 0x2) { cprint(LINE_CPU+6, col2, "3-"); } - else { cprint(LINE_CPU+6, col2, "6-"); } + if (temp == 0x0) { cas = 5; } + else if (temp == 0x1) { cas = 4; } + else if (temp == 0x2) { cas = 3; } + else { cas = 6; } } else { // Timings DDR-I - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "3-"); } - else if (temp == 0x1) { cprint(LINE_CPU+6, col2, "2.5-"); col2 +=2;} - else { cprint(LINE_CPU+6, col2, "2-"); } + if (temp == 0x0) { cas = 3; } + else if (temp == 0x1) { cas = 2.5f;} + else { cas = 2; } } - col2 +=2; // RAS-To-CAS (tRCD) - dprint(LINE_CPU+6, col2, ((drt >> 4)& 0x3)+2, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - col2 +=2; + rcd = ((drt >> 4)& 0x3)+2; // RAS Precharge (tRP) - dprint(LINE_CPU+6, col2, (drt&0x3)+2, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - col2 +=2; + rp = (drt&0x3)+2; // RAS Active to precharge (tRAS) // If Lakeport, than change tRAS computation (Thanks to CDH, again) if (idetect > 0x2700) - temp = ((drt >> 19)& 0x1F); + ras = ((drt >> 19)& 0x1F); else - temp = ((drt >> 20)& 0x0F); + ras = ((drt >> 20)& 0x0F); - dprint(LINE_CPU+6, col2, temp , 1 ,0); - (temp < 10)?(col2 += 1):(col2 += 2); - - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; temp = (dcc&0x3); - if (temp == 1) { cprint(LINE_CPU+6, col2, " Dual Channel (Asymmetric)"); } - else if (temp == 2) { cprint(LINE_CPU+6, col2, " Dual Channel (Interleaved)"); } - else { cprint(LINE_CPU+6, col2, " Single Channel (64 bits)"); } + if (temp == 1) { chan = 2; } + else if (temp == 2) { chan = 2; } + else { chan = 1; } + + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_i965(void) { // Thanks for CDH optis - ulong dev0, temp, c0ckectrl, c1ckectrl, offset; - ulong ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register; + ulong dev0, c0ckectrl, c1ckectrl, offset; + ulong ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register; long *ptr; + int rcd,rp,ras,chan; + float cas; //Now, read MMR Base Address pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); @@ -2608,56 +2988,37 @@ static void poll_timings_i965(void) { ptr = (long*)(dev0+offset+0x258); Read_Register = *ptr & 0xFFFFFFFF; - ptr = (long*)(dev0+offset+0x244); - Misc_Register = *ptr & 0xFFFFFFFF; - - //Intel 965 Series only support DDR2 - cprint(LINE_CPU+5, col +1, "- Type : DDR-II"); - - // Now, detect timings - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; // CAS Latency (tCAS) - temp = ((ODT_Control_Register >> 17)& 7) + 3.0f; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - (temp < 10)?(col2 += 2):(col2 += 3); + cas = ((ODT_Control_Register >> 17)& 7) + 3.0f; // RAS-To-CAS (tRCD) - temp = (Read_Register >> 16) & 0xF; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - (temp < 10)?(col2 += 2):(col2 += 3); + rcd = (Read_Register >> 16) & 0xF; // RAS Precharge (tRP) - temp = (ACT_Register >> 13) & 0xF; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - (temp < 10)?(col2 += 2):(col2 += 3); + rp = (ACT_Register >> 13) & 0xF; // RAS Active to precharge (tRAS) - temp = (Precharge_Register >> 11) & 0x1F; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - (temp < 10)?(col2 += 1):(col2 += 2); - - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; + ras = (Precharge_Register >> 11) & 0x1F; if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF)) { - cprint(LINE_CPU+6, col2+1, "Dual Channel"); + chan = 2; } else { - cprint(LINE_CPU+6, col2+1, "Single Channel"); + chan = 1; } + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_im965(void) { // Thanks for CDH optis - ulong dev0, temp, c0ckectrl, c1ckectrl, offset; + ulong dev0, c0ckectrl, c1ckectrl, offset; ulong ODT_Control_Register, Precharge_Register; long *ptr; - + int rcd,rp,ras,chan; + float cas; + //Now, read MMR Base Address pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); dev0 &= 0xFFFFC000; @@ -2677,55 +3038,36 @@ static void poll_timings_im965(void) { ptr = (long*)(dev0+offset+0x1214); Precharge_Register = *ptr & 0xFFFFFFFF; - //Intel 965 Series only support DDR2 - cprint(LINE_CPU+5, col+1, "- Type : DDR-II"); - - // Now, detect timings - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; - // CAS Latency (tCAS) - temp = ((ODT_Control_Register >> 23)& 7) + 3.0f; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - (temp < 10)?(col2 += 2):(col2 += 3); + cas = ((ODT_Control_Register >> 23)& 7) + 3.0f; // RAS-To-CAS (tRCD) - temp = ((Precharge_Register >> 5)& 7) + 2.0f; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - (temp < 10)?(col2 += 2):(col2 += 3); + rcd = ((Precharge_Register >> 5)& 7) + 2.0f; // RAS Precharge (tRP) - temp = (Precharge_Register & 7) + 2.0f; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - (temp < 10)?(col2 += 2):(col2 += 3); + rp = (Precharge_Register & 7) + 2.0f; // RAS Active to precharge (tRAS) - temp = (Precharge_Register >> 21) & 0x1F; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - (temp < 10)?(col2 += 1):(col2 += 2); + ras = (Precharge_Register >> 21) & 0x1F; - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF)) { - cprint(LINE_CPU+6, col2+1, "Dual Channel"); + chan = 2; } else { - cprint(LINE_CPU+6, col2+1, "Single Channel"); + chan = 1; } - + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_p35(void) { // Thanks for CDH optis float cas; - int rcd, rp, ras; - ulong dev0, Device_ID, Memory_Check, c0ckectrl, c1ckectrl, offset; - ulong ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register; + int rcd, rp, ras, chan; + ulong dev0, Device_ID, c0ckectrl, c1ckectrl, offset; + ulong ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register; long *ptr; - + pci_conf_read( 0, 0, 0, 0x02, 2, &Device_ID); Device_ID &= 0xFFFF; @@ -2754,30 +3096,9 @@ static void poll_timings_p35(void) { ptr = (long*)(dev0+offset+0x258); Read_Register = *ptr & 0xFFFFFFFF; - ptr = (long*)(dev0+offset+0x244); - Misc_Register = *ptr & 0xFFFFFFFF; - - // On P45, check 1A8 - if(Device_ID > 0x2E00) { - ptr = (long*)(dev0+offset+0x1A8); - Memory_Check = *ptr & 0xFFFFFFFF; - Memory_Check >>= 2; - Memory_Check &= 1; - Memory_Check = !Memory_Check; - } else { - ptr = (long*)(dev0+offset+0x1E8); - Memory_Check = *ptr & 0xFFFFFFFF; - } - - //Determine DDR-II or DDR-III - if (Memory_Check & 1) { - cprint(LINE_CPU+5, col +1, "- Type : DDR2"); - } else { - cprint(LINE_CPU+5, col +1, "- Type : DDR3"); - } // CAS Latency (tCAS) - if(Device_ID > 0x2E00) { + if(Device_ID > 0x2E00 && imc_type != 8) { cas = ((ODT_Control_Register >> 8)& 0x3F) - 6.0f; } else { cas = ((ODT_Control_Register >> 8)& 0x3F) - 9.0f; @@ -2792,22 +3113,18 @@ static void poll_timings_p35(void) { // RAS Active to precharge (tRAS) ras = Precharge_Register & 0x3F; - print_timings_info(cas, rcd, rp, ras); - - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; - if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF)) { - cprint(LINE_CPU+6, col2+1, "Dual Channel"); + chan = 2; } else { - cprint(LINE_CPU+6, col2+1, "Single Channel"); + chan = 1; } - + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_wmr(void) { float cas; - int rcd, rp, ras; + int rcd, rp, ras, chan; ulong dev0, c0ckectrl, c1ckectrl, offset; ulong ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, MRC_Register; long *ptr; @@ -2856,22 +3173,20 @@ static void poll_timings_wmr(void) { // RAS Active to precharge (tRAS) ras = Precharge_Register & 0x3F; - print_timings_info(cas, rcd, rp, ras); - - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; - if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF)) { - cprint(LINE_CPU+6, col2+1, "Dual Channel"); + chan = 2; } else { - cprint(LINE_CPU+6, col2+1, "Single Channel"); + chan = 1; } + print_ram_line(cas, rcd, rp, ras, chan); + } static void poll_timings_snb(void) { float cas; - int rcd, rp, ras; + int rcd, rp, ras, chan; ulong dev0, offset; ulong IMC_Register, MCMain0_Register, MCMain1_Register; long *ptr; @@ -2897,30 +3212,127 @@ static void poll_timings_snb(void) { // RAS Active to precharge (tRAS) ras = (IMC_Register >> 16) & 0xFF; - print_timings_info(cas, rcd, rp, ras); + // Channels + ptr = (long*)(dev0+offset+0x5004); + MCMain0_Register = *ptr & 0xFFFF; + ptr = (long*)(dev0+offset+0x5008); + MCMain1_Register = *ptr & 0xFFFF; + + if(MCMain0_Register == 0 || MCMain1_Register == 0) { + chan = 1; + } else { + chan = 2; + } + + print_ram_line(cas, rcd, rp, ras, chan); +} - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; +static void poll_timings_hsw(void) { + + float cas; + int rcd, rp, ras, chan; + ulong dev0, offset = 0; + ulong IMC_Register, MCMain0_Register, MCMain1_Register; + long *ptr; + + //Now, read MMR Base Address + pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); + dev0 &= 0xFFFFC000; // Channels ptr = (long*)(dev0+offset+0x5004); MCMain0_Register = *ptr & 0xFFFF; + ptr = (long*)(dev0+offset+0x5008); MCMain1_Register = *ptr & 0xFFFF; - if(MCMain0_Register == 0 || MCMain1_Register == 0) { - cprint(LINE_CPU+6, col2+1, "Single Channel"); + if(MCMain0_Register && MCMain1_Register) { + chan = 2; } else { - cprint(LINE_CPU+6, col2+1, "Dual Channel"); + chan = 1; } + + if(MCMain0_Register) { offset = 0x0000; } else { offset = 0x0400; } + + // CAS Latency (tCAS) + ptr = (long*)(dev0+offset+0x4014); + IMC_Register = *ptr & 0xFFFFFFFF; + cas = (float)(IMC_Register & 0x1F); + + ptr = (long*)(dev0+offset+0x4000); + IMC_Register = *ptr & 0xFFFFFFFF; + + // RAS-To-CAS (tRCD) + rcd = IMC_Register & 0x1F; + + // RAS Precharge (tRP) + rp = (IMC_Register >> 5) & 0x1F; + + // RAS Active to precharge (tRAS) + ras = (IMC_Register >> 10) & 0x3F; + + + print_ram_line(cas, rcd, rp, ras, chan); +} + +static void poll_timings_snbe(void) { + + float cas; + int rcd, rp, ras; + int nb_channel = 0, current_channel = 0; + ulong temp, IMC_Register; + long *ptr; + + //Read Channel #1 + pci_conf_read(0xFF, 16, 2, 0x80, 4, &temp); + temp &= 0x3F; + if(temp != 0xB) { current_channel = 0; nb_channel++; } + + //Read Channel #2 + pci_conf_read(0xFF, 16, 3, 0x80, 4, &temp); + temp &= 0x3F; + if(temp != 0xB) { current_channel = 1; nb_channel++; } + + //Read Channel #3 + pci_conf_read(0xFF, 16, 6, 0x80, 4, &temp); + temp &= 0x3F; + if(temp != 0xB) { current_channel = 4; nb_channel++; } + + //Read Channel #4 + pci_conf_read(0xFF, 16, 7, 0x80, 4, &temp); + temp &= 0x3F; + if(temp != 0xB) { current_channel = 5; nb_channel++; } + + + pci_conf_read(0, 5, 0, 0x84, 4, &temp); + ptr = (long*)((temp & 0xFC000000) + (MAKE_PCIE_ADDRESS(0xFF,16,current_channel) | 0x200)); + IMC_Register = *ptr & 0xFFFFFFFF; + + // CAS Latency (tCAS) + cas = (float)((IMC_Register >> 9) & 0x1F); + + // RAS-To-CAS (tRCD) + rcd = IMC_Register & 0x1F; + + // RAS Precharge (tRP) + rp = (IMC_Register >> 5) & 0x0F; + + // RAS Active to precharge (tRAS) + ras = (IMC_Register >> 19) & 0x3F; + + + print_ram_line(cas, rcd, rp, ras, nb_channel); } static void poll_timings_5400(void) { // Thanks for CDH optis - ulong ambase, mtr1, mtr2, offset, mca, temp; + ulong ambase, mtr1, mtr2, offset, mca; long *ptr; - + float cas; + int rcd, rp, ras, chan; + //Hard-coded Ambase value (should not be realocated by software when using Memtest86+ ambase = 0xFE000000; offset = mtr1 = mtr2 = 0; @@ -2942,49 +3354,36 @@ static void poll_timings_5400(void) { //cprint(LINE_CPU+5, col +1, "- Type : FBD"); // Now, detect timings - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; // CAS Latency (tCAS) - temp = mtr2 & 0xF; - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - col2 += 2; + cas = mtr2 & 0xF; // RAS-To-CAS (tRCD) - temp = 6 - ((mtr1 >> 10) & 3); - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - col2 += 2; + rcd = 6 - ((mtr1 >> 10) & 3); // RAS Precharge (tRP) - temp = 6 - ((mtr1 >> 8) & 3); - dprint(LINE_CPU+6, col2, temp, 1 ,0); - cprint(LINE_CPU+6, col2+1, "-"); - col2 += 2; + rp = 6 - ((mtr1 >> 8) & 3); // RAS Active to precharge (tRAS) - temp = 16 - (3 * ((mtr1 >> 29) & 3)) + ((mtr1 >> 12) & 3); - if(((mtr1 >> 12) & 3) == 3 && ((mtr1 >> 29) & 3) == 2) { temp = 9; } - - dprint(LINE_CPU+6, col2, temp, 1 ,0); - (temp < 10)?(col2 += 1):(col2 += 2); + ras = 16 - (3 * ((mtr1 >> 29) & 3)) + ((mtr1 >> 12) & 3); + if(((mtr1 >> 12) & 3) == 3 && ((mtr1 >> 29) & 3) == 2) { ras = 9; } - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; if ((mca >> 14) & 1) { - cprint(LINE_CPU+6, col2+1, "Single Channel"); + chan = 1; } else { - cprint(LINE_CPU+6, col2+1, "Dual Channel"); + chan = 2; } + print_ram_line(cas, rcd, rp, ras, chan); + } static void poll_timings_E7520(void) { ulong drt, ddrcsr; float cas; - int rcd, rp, ras; + int rcd, rp, ras, chan; pci_conf_read( 0, 0, 0, 0x78, 4, &drt); pci_conf_read( 0, 0, 0, 0x9A, 2, &ddrcsr); @@ -2993,21 +3392,23 @@ static void poll_timings_E7520(void) { rcd = ((drt >> 10) & 1) + 3; rp = ((drt >> 9) & 1) + 3; ras = ((drt >> 14) & 3) + 11; - - print_timings_info(cas, rcd, rp, ras); if ((ddrcsr & 0xF) >= 0xC) { - cprint(LINE_CPU+6, col2, "/ Dual Channel (128 bits)"); + chan = 2; } else { - cprint(LINE_CPU+6, col2, "/ Single Channel (64 bits)"); + chan = 1; } + + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_i855(void) { ulong drt, temp; - + float cas; + int rcd, rp, ras; + pci_conf_read( 0, 0, 0, 0x78, 4, &drt); /* Now, we could print some additionnals timings infos) */ @@ -3016,27 +3417,26 @@ static void poll_timings_i855(void) { // CAS Latency (tCAS) temp = ((drt >> 4)&0x1); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "2.5-"); col2 += 4; } - else { cprint(LINE_CPU+6, col2, "2-"); col2 +=2; } + if (temp == 0x0) { cas = 2.5; } + else { cas = 2; } // RAS-To-CAS (tRCD) temp = ((drt >> 2)& 0x1); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "3-"); } - else { cprint(LINE_CPU+6, col2, "2-"); } - col2 +=2; + if (temp == 0x0) { rcd = 3; } + else { rcd = 2; } // RAS Precharge (tRP) temp = (drt&0x1); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "3-"); } - else { cprint(LINE_CPU+6, col2, "2-"); } - col2 +=2; + if (temp == 0x0) { rp = 3 ; } + else { rp = 2; } // RAS Active to precharge (tRAS) temp = 7-((drt >> 9)& 0x3); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "7"); } - if (temp == 0x1) { cprint(LINE_CPU+6, col2, "6"); } - if (temp == 0x2) { cprint(LINE_CPU+6, col2, "5"); } - col2 +=1; + if (temp == 0x0) { ras = 7; } + if (temp == 0x1) { ras = 6; } + if (temp == 0x2) { ras = 5; } + + print_ram_line(cas, rcd, rp, ras, 1); } @@ -3044,7 +3444,7 @@ static void poll_timings_E750x(void) { ulong drt, drc, temp; float cas; - int rcd, rp, ras; + int rcd, rp, ras, chan; pci_conf_read( 0, 0, 0, 0x78, 4, &drt); pci_conf_read( 0, 0, 0, 0x7C, 4, &drc); @@ -3056,20 +3456,22 @@ static void poll_timings_E750x(void) { temp = ((drt >> 9) & 3); if (temp == 2) { ras = 5; } else if (temp == 1) { ras = 6; } else { ras = 7; } - print_timings_info(cas, rcd, rp, ras); - if (((drc >> 22)&1) == 1) { - cprint(LINE_CPU+6, col2, "/ Dual Channel (128 bits)"); + chan = 2; } else { - cprint(LINE_CPU+6, col2, "/ Single Channel (64 bits)"); + chan = 1; } + print_ram_line(cas, rcd, rp, ras, chan); + } static void poll_timings_i852(void) { ulong drt, temp; - + float cas; + int rcd, rp, ras; + pci_conf_read( 0, 0, 1, 0x60, 4, &drt); /* Now, we could print some additionnals timings infos) */ @@ -3078,80 +3480,62 @@ static void poll_timings_i852(void) { // CAS Latency (tCAS) temp = ((drt >> 5)&0x1); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "2.5-"); col2 += 4; } - else { cprint(LINE_CPU+6, col2, "2-"); col2 +=2; } + if (temp == 0x0) { cas = 2.5; } + else { cas = 2; } // RAS-To-CAS (tRCD) temp = ((drt >> 2)& 0x3); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "4-"); } - if (temp == 0x1) { cprint(LINE_CPU+6, col2, "3-"); } - else { cprint(LINE_CPU+6, col2, "2-"); } - col2 +=2; + if (temp == 0x0) { rcd = 4; } + if (temp == 0x1) { rcd = 3; } + else { rcd = 2; } // RAS Precharge (tRP) temp = (drt&0x3); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "4-"); } - if (temp == 0x1) { cprint(LINE_CPU+6, col2, "3-"); } - else { cprint(LINE_CPU+6, col2, "2-"); } - col2 +=2; + if (temp == 0x0) { rp = 4; } + if (temp == 0x1) { rp = 3; } + else { rp = 2; } // RAS Active to precharge (tRAS) temp = ((drt >> 9)& 0x3); - if (temp == 0x0) { cprint(LINE_CPU+6, col2, "8"); col2 +=7; } - if (temp == 0x1) { cprint(LINE_CPU+6, col2, "7"); col2 +=6; } - if (temp == 0x2) { cprint(LINE_CPU+6, col2, "6"); col2 +=5; } - if (temp == 0x3) { cprint(LINE_CPU+6, col2, "5"); col2 +=5; } - col2 +=1; + if (temp == 0x0) { ras = 8; } + if (temp == 0x1) { ras = 7; } + if (temp == 0x2) { ras = 6; } + if (temp == 0x3) { ras = 5; } + + print_ram_line(cas, rcd, rp, ras, 1); } static void poll_timings_amd64(void) { ulong dramtlr, dramclr; - int temp; + int temp, chan; + float tcas; int trcd, trp, tras ; - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; - pci_conf_read(0, 24, 2, 0x88, 4, &dramtlr); pci_conf_read(0, 24, 2, 0x90, 4, &dramclr); - - if (((cpu_id.ext >> 16) & 0xF) >= 4) { + + if (cpu_id.vers.bits.extendedModel >= 4) { /* NEW K8 0Fh Family 90 nm (DDR2) */ // CAS Latency (tCAS) - temp = (dramtlr & 0x7) + 1; - dprint(LINE_CPU+6, col2, temp , 1 ,0); - cprint(LINE_CPU+6, col2 +1, "-"); col2 +=2; + tcas = (dramtlr & 0x7) + 1; // RAS-To-CAS (tRCD) trcd = ((dramtlr >> 4) & 0x3) + 3; - dprint(LINE_CPU+6, col2, trcd , 1 ,0); - cprint(LINE_CPU+6, col2 +1, "-"); col2 +=2; // RAS Precharge (tRP) trp = ((dramtlr >> 8) & 0x3) + 3; - dprint(LINE_CPU+6, col2, trp , 1 ,0); - cprint(LINE_CPU+6, col2 +1, "-"); col2 +=2; // RAS Active to precharge (tRAS) tras = ((dramtlr >> 12) & 0xF) + 3; - if (tras < 10){ - dprint(LINE_CPU+6, col2, tras , 1 ,0); col2 += 1; - } else { - dprint(LINE_CPU+6, col2, tras , 2 ,0); col2 += 2; - } - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; // Print 64 or 128 bits mode - if ((dramclr >> 11)&1) { - cprint(LINE_CPU+6, col2, " DDR2 (128 bits)"); - col2 +=16; + chan = 2; } else { - cprint(LINE_CPU+6, col2, " DDR2 (64 bits)"); - col2 +=15; + chan = 1; } } else { @@ -3159,48 +3543,41 @@ static void poll_timings_amd64(void) { // CAS Latency (tCAS) temp = (dramtlr & 0x7); - if (temp == 0x1) { cprint(LINE_CPU+6, col2, "2-"); col2 +=2; } - if (temp == 0x2) { cprint(LINE_CPU+6, col2, "3-"); col2 +=2; } - if (temp == 0x5) { cprint(LINE_CPU+6, col2, "2.5-"); col2 +=4; } + if (temp == 0x1) { tcas = 2; } + if (temp == 0x2) { tcas = 3; } + if (temp == 0x5) { tcas = 2.5; } // RAS-To-CAS (tRCD) trcd = ((dramtlr >> 12) & 0x7); - dprint(LINE_CPU+6, col2, trcd , 1 ,0); - cprint(LINE_CPU+6, col2 +1, "-"); col2 +=2; // RAS Precharge (tRP) trp = ((dramtlr >> 24) & 0x7); - dprint(LINE_CPU+6, col2, trp , 1 ,0); - cprint(LINE_CPU+6, col2 +1, "-"); col2 +=2; // RAS Active to precharge (tRAS) tras = ((dramtlr >> 20) & 0xF); - if (tras < 10){ - dprint(LINE_CPU+6, col2, tras , 1 ,0); col2 += 1; - } else { - dprint(LINE_CPU+6, col2, tras , 2 ,0); col2 += 2; - } - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; // Print 64 or 128 bits mode - if (((dramclr >> 16)&1) == 1) { - cprint(LINE_CPU+6, col2, " DDR1 (128 bits)"); - col2 +=16; + chan = 2; } else { - cprint(LINE_CPU+6, col2, " DDR1 (64 bits)"); - col2 +=15; + chan = 1; } } + + print_ram_line(tcas, trcd, trp, tras, chan); + } static void poll_timings_k10(void) { - ulong dramtlr, dramclr, dramchr; + ulong dramtlr, dramclr, dramchr, dramchrb; ulong offset = 0; - int cas, rcd, rp, rc, ras; + int cas, rcd, rp, ras, chan; pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); + pci_conf_read(0, 24, 2, 0x194, 4, &dramchrb); + + if(((dramchr>>14) & 0x1) || ((dramchr>>14) & 0x1)) { chan = 1; } else { chan = 2; } // If Channel A not enabled, switch to channel B if(((dramchr>>14) & 0x1)) @@ -3218,57 +3595,104 @@ static void poll_timings_k10(void) { cas = (dramtlr & 0xF) + 4; rcd = ((dramtlr >> 4) & 0x7) + 5; rp = ((dramtlr >> 7) & 0x7) + 5; - ras = ((dramtlr >> 12) & 0xF) + 15; - rc = ((dramtlr >> 16) & 0x1F) + 11; + ras = ((dramtlr >> 12) & 0xF) + 15; } else { // DDR2-800 or less cas = (dramtlr & 0xF) + 1; rcd = ((dramtlr >> 4) & 0x3) + 3; rp = ((dramtlr >> 8) & 0x3) + 3; ras = ((dramtlr >> 12) & 0xF) + 3; - rc = ((dramtlr >> 16) & 0x1F) + 11; } + + print_ram_line(cas, rcd, rp, ras, chan); +} - print_timings_info(cas, rcd, rp, ras); - - cprint(LINE_CPU+6, col2, "/"); col2++; +static void poll_timings_k12(void) { + + ulong dramt0, dramlow, dimma, dimmb; + int cas, rcd, rp, ras, chan = 0; - //Print DDR2 or DDR3 - if ((dramchr >> 8)&1) { - cprint(LINE_CPU+6, col2+1, "DDR3"); - } else { - cprint(LINE_CPU+6, col2+1, "DDR2"); + pci_conf_read(0, 24, 2, 0x94, 4, &dimma); + pci_conf_read(0, 24, 2, 0x194, 4, &dimmb); + + if(((dimma >> 14) & 0x1) == 0) + { + chan++; + pci_conf_read(0, 24, 2, 0x88, 4, &dramlow); + pci_conf_write(0, 24, 2, 0xF0, 4, 0x00000040); + pci_conf_read(0, 24, 2, 0xF4, 4, &dramt0); } - col2 += 5; - // Print 64 or 128 bits mode - if ((dramclr >> 4)&1) { - cprint(LINE_CPU+6, col2+1, "(128 bits)"); - } else { - cprint(LINE_CPU+6, col2+1, "(64 bits)"); - } + if(((dimmb >> 14) & 0x1) == 0) + { + chan++; + pci_conf_read(0, 24, 2, 0x188, 4, &dramlow); + pci_conf_write(0, 24, 2, 0x1F0, 4, 0x00000040); + pci_conf_read(0, 24, 2, 0x1F4, 4, &dramt0); + } + + cas = (dramlow & 0xF) + 4; + rcd = (dramt0 & 0xF) + 5; + rp = ((dramt0 >> 8) & 0xF) + 5; + ras = ((dramt0 >> 16) & 0x1F) + 15; + print_ram_line(cas, rcd, rp, ras, chan); } + static void poll_timings_k14(void) { ulong dramt0, dramlow; - int cas, rcd, rp, rc, ras; + int cas, rcd, rp, ras; - pci_conf_read(0, 24, 2, 0x88, 4, &dramlow); + pci_conf_read(0, 24, 2, 0x88, 4, &dramlow); pci_conf_write(0, 24, 2, 0xF0, 4, 0x00000040); - pci_conf_read(0, 24, 2, 0xF4, 4, &dramt0); + pci_conf_read(0, 24, 2, 0xF4, 4, &dramt0); cas = (dramlow & 0xF) + 4; rcd = (dramt0 & 0xF) + 5; rp = ((dramt0 >> 8) & 0xF) + 5; ras = ((dramt0 >> 16) & 0x1F) + 15; - rc = ((dramt0 >> 24) & 0x3F) + 16; + + print_ram_line(cas, rcd, rp, ras, 1); +} - print_timings_info(cas, rcd, rp, ras); +static void poll_timings_k15(void) { - cprint(LINE_CPU+6, col2, "/ DDR3 (64 bits)"); + ulong dramp1, dramp2, dimma, dimmb; + int cas, rcd, rp, ras, chan = 0; + + pci_conf_read(0, 24, 2, 0x94, 4, &dimma); + pci_conf_read(0, 24, 2, 0x194, 4, &dimmb); + if(((dimma>>14) & 0x1) || ((dimmb>>14) & 0x1)) { chan = 1; } else { chan = 2; } + + pci_conf_read(0, 24, 2, 0x200, 4, &dramp1); + pci_conf_read(0, 24, 2, 0x204, 4, &dramp2); + + cas = dramp1 & 0x1F; + rcd = (dramp1 >> 8) & 0x1F; + rp = (dramp1 >> 16) & 0x1F; + ras = (dramp1 >> 24) & 0x3F; + + print_ram_line(cas, rcd, rp, ras, chan); +} +static void poll_timings_k16(void) { + + ulong dramt0, dramt1; + int cas, rcd, rp, rc, ras; + + pci_conf_read(0, 24, 2, 0x200, 4, &dramt0); + pci_conf_read(0, 24, 2, 0x204, 4, &dramt1); + + cas = (dramt0 & 0x1F); + rcd = ((dramt0 >> 8) & 0x1F); + rp = ((dramt0 >> 16) & 0x1F); + ras = ((dramt0 >> 24) & 0x3F); + + rc = (dramt1 & 0x3F); + + print_ram_line(cas, rcd, rp, ras, 1); } static void poll_timings_EP80579(void) { @@ -3285,14 +3709,16 @@ static void poll_timings_EP80579(void) { rp = ((drt1 >> 6) & 0x7) + 3; ras = ((drt2 >> 28) & 0xF) + 8; - print_timings_info(cas, rcd, rp, ras); + print_ram_line(cas, rcd, rp, ras, 0); } static void poll_timings_nf2(void) { ulong dramtlr, dramtlr2, dramtlr3, temp; ulong dimm1p, dimm2p, dimm3p; - + float cas; + int rcd, rp, ras, chan; + pci_conf_read(0, 0, 1, 0x90, 4, &dramtlr); pci_conf_read(0, 0, 1, 0xA0, 4, &dramtlr2); pci_conf_read(0, 0, 1, 0x84, 4, &dramtlr3); @@ -3300,77 +3726,54 @@ static void poll_timings_nf2(void) { pci_conf_read(0, 0, 2, 0x44, 4, &dimm2p); pci_conf_read(0, 0, 2, 0x48, 4, &dimm3p); - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; - // CAS Latency (tCAS) temp = ((dramtlr2 >> 4) & 0x7); - if (temp == 0x2) { cprint(LINE_CPU+6, col2, "2-"); col2 +=2; } - if (temp == 0x3) { cprint(LINE_CPU+6, col2, "3-"); col2 +=2; } - if (temp == 0x6) { cprint(LINE_CPU+6, col2, "2.5-"); col2 +=4; } - + if (temp == 0x2) { cas = 2; } + if (temp == 0x3) { cas = 3; } + if (temp == 0x6) { cas = 2.5; } + // RAS-To-CAS (tRCD) - temp = ((dramtlr >> 20) & 0xF); - dprint(LINE_CPU+6, col2, temp , 1 ,0); - cprint(LINE_CPU+6, col2 +1, "-"); col2 +=2; + rcd = ((dramtlr >> 20) & 0xF); // RAS Precharge (tRP) - temp = ((dramtlr >> 28) & 0xF); - dprint(LINE_CPU+6, col2, temp , 1 ,0); - cprint(LINE_CPU+6, col2 +1, "-"); col2 +=2; + rp = ((dramtlr >> 28) & 0xF); // RAS Active to precharge (tRAS) - temp = ((dramtlr >> 15) & 0xF); - if (temp < 10){ - dprint(LINE_CPU+6, col2, temp , 1 ,0); col2 += 1; - } else { - dprint(LINE_CPU+6, col2, temp , 2 ,0); col2 += 2; - } - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; + ras = ((dramtlr >> 15) & 0xF); // Print 64 or 128 bits mode // If DIMM1 & DIMM3 or DIMM1 & DIMM2 populated, than Dual Channel. if ((dimm3p&1) + (dimm2p&1) == 2 || (dimm3p&1) + (dimm1p&1) == 2 ) { - cprint(LINE_CPU+6, col2, " Dual Channel (128 bits)"); - col2 +=24; + chan = 2; } else { - cprint(LINE_CPU+6, col2, " Single Channel (64 bits)"); - col2 +=15; + chan = 1; } - + print_ram_line(cas, rcd, rp, ras, chan); } static void poll_timings_us15w(void) { // Thanks for CDH optis - ulong dtr, temp; - + ulong dtr; + float cas; + int rcd, rp; + /* Find dramratio */ /* D0 MsgRd, 01 Dunit, 01 DTR */ pci_conf_write(0, 0, 0, 0xD0, 4, 0xD0010100 ); pci_conf_read(0, 0, 0, 0xD4, 4, &dtr ); - // Now, detect timings - cprint(LINE_CPU+5, col2 +1, "/ CAS : "); - col2 += 9; - // CAS Latency (tCAS) - temp = ((dtr >> 4) & 0x3) + 3; - dprint(LINE_CPU+5, col2, temp, 1 ,0); - cprint(LINE_CPU+5, col2+1, "-"); - col2 += 2; + cas = ((dtr >> 4) & 0x3) + 3; // RAS-To-CAS (tRCD) - temp = ((dtr >> 2) & 0x3) + 3; - dprint(LINE_CPU+5, col2, temp, 1 ,0); - cprint(LINE_CPU+5, col2+1, "-"); - col2 += 2; + rcd = ((dtr >> 2) & 0x3) + 3; // RAS Precharge (tRP) - temp = ((dtr >> 0) & 0x3) + 3; - dprint(LINE_CPU+5, col2, temp, 1 ,0); - col2 += 1; + rp = ((dtr >> 0) & 0x3) + 3; + + print_ram_line(cas, rcd, rp, 9, 1); } @@ -3378,7 +3781,7 @@ static void poll_timings_nhm(void) { ulong mc_channel_bank_timing, mc_control, mc_channel_mrs_value; float cas; - int rcd, rp, ras; + int rcd, rp, ras, chan; int fvc_bn = 4; /* Find which channels are populated */ @@ -3403,200 +3806,233 @@ static void poll_timings_nhm(void) { ras = (mc_channel_bank_timing >> 4) & 0x1F; rp = mc_channel_bank_timing & 0xF; - print_timings_info(cas, rcd, rp, ras); - // Print 1, 2 or 3 Channels if (mc_control == 1 || mc_control == 2 || mc_control == 4 ) { - cprint(LINE_CPU+6, col2, "/ Single Channel"); - col2 += 16; + chan = 1; } else if (mc_control == 7) { - cprint(LINE_CPU+6, col2, "/ Triple Channel"); - col2 += 16; + chan = 3; } else { - cprint(LINE_CPU+6, col2, "/ Dual Channel"); - col2 += 14; + chan = 2; } - + print_ram_line(cas, rcd, rp, ras, chan); + } +static void poll_timings_ct(void) +{ + + unsigned long mcr,mdr; + float cas; + int rcd, rp, ras; + + /* Build the MCR Message*/ + mcr = (0x10 << 24); // 10h = Read - 11h = Write + mcr += (0x01 << 16); // DRAM Registers located on port 01h + mcr += (0x01 << 8); // DRP = 00h, DTR0 = 01h, DTR1 = 02h, DTR2 = 03h + mcr &= 0xFFFFFFF0; // bit 03:00 RSVD + + /* Send Message to GMCH */ + pci_conf_write(0, 0, 0, 0xD0, 4, mcr); + + /* Read Answer from Sideband bus */ + pci_conf_read(0, 0, 0, 0xD4, 4, &mdr); + + // CAS Latency (tCAS) + cas = ((mdr >> 12)& 0x7) + 5.0f; + + // RAS-To-CAS (tRCD) + rcd = ((mdr >> 8)& 0x7) + 5; + + // RAS Precharge (tRP) + rp = ((mdr >> 4)& 0x7) + 5; + + // RAS is in DTR1. Read Again. + mcr = 0x10010200; // Quick Mode ! Awesome ! + pci_conf_write(0, 0, 0, 0xD0, 4, mcr); + pci_conf_read(0, 0, 0, 0xD4, 4, &mdr); + + // RAS Active to precharge (tRAS) + ras = (mdr >> 20) & 0xF; + + // Print + print_ram_line(cas, rcd, rp, ras, 1); + +} /* ------------------ Let's continue ------------------ */ /* ---------------------------------------------------- */ -static struct pci_memory_controller controllers[] = { +struct pci_memory_controller controllers[] = { /* Default unknown chipset */ - { 0, 0, "", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0, 0, "","", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, /* AMD */ - { 0x1022, 0x7006, "AMD 751", 0, poll_fsb_nothing, poll_timings_nothing, setup_amd751, poll_amd751 }, - { 0x1022, 0x700c, "AMD 762", 0, poll_fsb_nothing, poll_timings_nothing, setup_amd76x, poll_amd76x }, - { 0x1022, 0x700e, "AMD 761", 0, poll_fsb_nothing, poll_timings_nothing, setup_amd76x, poll_amd76x }, + { 0x1022, 0x7006, "AMD 751","SDRAM PC-100", 0, poll_fsb_nothing, poll_timings_nothing, setup_amd751, poll_nothing }, + { 0x1022, 0x700c, "AMD 762","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_amd76x, poll_nothing }, + { 0x1022, 0x700e, "AMD 761","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_amd76x, poll_nothing }, /* SiS */ - { 0x1039, 0x0600, "SiS 600", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0620, "SiS 620", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x5600, "SiS 5600", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0645, "SiS 645", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0646, "SiS 645DX", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0630, "SiS 630", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0650, "SiS 650", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0651, "SiS 651", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0730, "SiS 730", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0735, "SiS 735", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0740, "SiS 740", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0745, "SiS 745", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0748, "SiS 748", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0655, "SiS 655", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0656, "SiS 656", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0648, "SiS 648", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0649, "SiS 649", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0661, "SiS 661", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0671, "SiS 671", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1039, 0x0672, "SiS 672", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0600, "SiS 600","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0620, "SiS 620","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x5600, "SiS 5600","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0645, "SiS 645","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0646, "SiS 645DX","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0630, "SiS 630","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0650, "SiS 650","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0651, "SiS 651","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0730, "SiS 730","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0735, "SiS 735","DDR-SDRAM", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0740, "SiS 740","DDR-SDRAM", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0745, "SiS 745","DDR-SDRAM", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0748, "SiS 748","DDR-SDRAM", 0, poll_fsb_amd32, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0655, "SiS 655","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0656, "SiS 656","DDR/DDR2-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0648, "SiS 648","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0649, "SiS 649","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0661, "SiS 661","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0671, "SiS 671","DDR2-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1039, 0x0672, "SiS 672","DDR2-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, /* ALi */ - { 0x10b9, 0x1531, "ALi Aladdin 4", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x10b9, 0x1541, "ALi Aladdin 5", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x10b9, 0x1644, "ALi Aladdin M1644", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x10b9, 0x1531, "ALi Aladdin 4","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x10b9, 0x1541, "ALi Aladdin 5","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x10b9, 0x1644, "ALi Aladdin M1644","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, /* ATi */ - { 0x1002, 0x5830, "ATi Radeon 9100 IGP", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1002, 0x5831, "ATi Radeon 9100 IGP", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1002, 0x5832, "ATi Radeon 9100 IGP", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1002, 0x5833, "ATi Radeon 9100 IGP", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1002, 0x5954, "ATi Radeon Xpress 200", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1002, 0x5A41, "ATi Radeon Xpress 200", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1002, 0x5830, "ATi Radeon 9100 IGP","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1002, 0x5831, "ATi Radeon 9100 IGP","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1002, 0x5832, "ATi Radeon 9100 IGP","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1002, 0x5833, "ATi Radeon 9100 IGP","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1002, 0x5954, "ATi Xpress 200","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1002, 0x5A41, "ATi Xpress 200","DDR-SDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, /* nVidia */ - { 0x10de, 0x01A4, "nVidia nForce", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x10de, 0x01E0, "nVidia nForce2 SPP", 0, poll_fsb_nf2, poll_timings_nf2, setup_nothing, poll_nothing }, - { 0x10de, 0x0071, "nForce4 SLI Intel Edition", 0, poll_fsb_nf4ie, poll_timings_nf4ie, setup_nothing, poll_nothing }, + { 0x10de, 0x01A4, "nVidia nForce","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x10de, 0x01E0, "nVidia nForce2 SPP","", 0, poll_fsb_nf2, poll_timings_nf2, setup_nothing, poll_nothing }, + { 0x10de, 0x0071, "nForce4 SLI","", 0, poll_fsb_nf4ie, poll_timings_nf4ie, setup_nothing, poll_nothing }, /* VIA */ - { 0x1106, 0x0305, "VIA KT133/KT133A", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0391, "VIA KX133", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0501, "VIA MVP4", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0585, "VIA VP/VPX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0595, "VIA VP2", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0597, "VIA VP3", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0598, "VIA MVP3", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0691, "VIA Apollo Pro/133/133A", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0693, "VIA Apollo Pro+", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0601, "VIA PLE133", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x3099, "VIA KT266(A)/KT333", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x3189, "VIA KT400(A)/600", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0269, "VIA KT880", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x3205, "VIA KM400", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x3116, "VIA KM266", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x3156, "VIA KN266", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x3123, "VIA CLE266", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x0198, "VIA PT800", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x1106, 0x3258, "VIA PT880", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0305, "VIA KT133/KT133A","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0391, "VIA KX133","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0501, "VIA MVP4","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0585, "VIA VP/VPX","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0595, "VIA VP2","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0597, "VIA VP3","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0598, "VIA MVP3","EDO/SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0691, "VIA Apollo Pro 133(A)","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0693, "VIA Apollo Pro+","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0601, "VIA PLE133","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x3099, "VIA KT266(A)/KT333","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x3189, "VIA KT400(A)/600","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0269, "VIA KT880","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x3205, "VIA KM400","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x3116, "VIA KM266","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x3156, "VIA KN266","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x3123, "VIA CLE266","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x0198, "VIA PT800","DDR-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x1106, 0x3258, "VIA PT880","DDR2-SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, /* Serverworks */ - { 0x1166, 0x0008, "CNB20HE", 0, poll_fsb_nothing, poll_timings_nothing, setup_cnb20, poll_nothing }, - { 0x1166, 0x0009, "CNB20LE", 0, poll_fsb_nothing, poll_timings_nothing, setup_cnb20, poll_nothing }, + { 0x1166, 0x0008, "CNB20HE","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_cnb20, poll_nothing }, + { 0x1166, 0x0009, "CNB20LE","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_cnb20, poll_nothing }, /* Intel */ - { 0x8086, 0x1130, "Intel i815", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x122d, "Intel i430FX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x1235, "Intel i430MX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x1237, "Intel i440FX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x1250, "Intel i430HX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x1A21, "Intel i840", 0, poll_fsb_nothing, poll_timings_nothing, setup_i840, poll_i840 }, - { 0x8086, 0x1A30, "Intel i845", 0, poll_fsb_p4, poll_timings_nothing, setup_i845, poll_i845 }, - { 0x8086, 0x2560, "Intel i845E/G/PE/GE",0, poll_fsb_p4, poll_timings_nothing, setup_i845, poll_i845 }, - { 0x8086, 0x2500, "Intel i820", 0, poll_fsb_nothing, poll_timings_nothing, setup_i820, poll_i820 }, - { 0x8086, 0x2530, "Intel i850", 0, poll_fsb_p4, poll_timings_nothing, setup_i850, poll_i850 }, - { 0x8086, 0x2531, "Intel i860", 1, poll_fsb_nothing, poll_timings_nothing, setup_i860, poll_i860 }, - { 0x8086, 0x7030, "Intel i430VX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x7100, "Intel i430TX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x7120, "Intel i810", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x7122, "Intel i810", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x7124, "Intel i810E", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x7180, "Intel i440[LE]X", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x7190, "Intel i440BX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x7192, "Intel i440BX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x71A0, "Intel i440GX", 0, poll_fsb_nothing, poll_timings_nothing, setup_i440gx, poll_i440gx }, - { 0x8086, 0x71A2, "Intel i440GX", 0, poll_fsb_nothing, poll_timings_nothing, setup_i440gx, poll_i440gx }, - { 0x8086, 0x84C5, "Intel i450GX", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x2540, "Intel E7500", 1, poll_fsb_p4, poll_timings_E750x, setup_iE7xxx, poll_iE7xxx }, - { 0x8086, 0x254C, "Intel E7501", 1, poll_fsb_p4, poll_timings_E750x, setup_iE7xxx, poll_iE7xxx }, - { 0x8086, 0x255d, "Intel E7205", 0, poll_fsb_p4, poll_timings_nothing, setup_iE7xxx, poll_iE7xxx }, - { 0x8086, 0x3592, "Intel E7320", 0, poll_fsb_p4, poll_timings_E7520, setup_iE7520, poll_iE7520 }, - { 0x8086, 0x2588, "Intel E7221", 1, poll_fsb_i925, poll_timings_i925, setup_i925, poll_iE7221 }, - { 0x8086, 0x3590, "Intel E7520", 0, poll_fsb_p4, poll_timings_E7520, setup_iE7520, poll_nothing }, - { 0x8086, 0x2600, "Intel E8500", 0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, - { 0x8086, 0x2570, "Intel i848/i865", 0, poll_fsb_i875, poll_timings_i875, setup_i875, poll_nothing }, - { 0x8086, 0x2578, "Intel i875P", 0, poll_fsb_i875, poll_timings_i875, setup_i875, poll_i875 }, - { 0x8086, 0x2550, "Intel E7505", 0, poll_fsb_p4, poll_timings_nothing, setup_iE7xxx, poll_iE7xxx }, - { 0x8086, 0x3580, "Intel ", 0, poll_fsb_i855, poll_timings_i852, setup_nothing, poll_nothing }, - { 0x8086, 0x3340, "Intel i855PM", 0, poll_fsb_i855, poll_timings_i855, setup_nothing, poll_nothing }, - { 0x8086, 0x2580, "Intel i915P/G", 0, poll_fsb_i925, poll_timings_i925, setup_i925, poll_nothing }, - { 0x8086, 0x2590, "Intel i915PM/GM", 0, poll_fsb_i925, poll_timings_i925, setup_i925, poll_nothing }, - { 0x8086, 0x2584, "Intel i925X/XE", 0, poll_fsb_i925, poll_timings_i925, setup_i925, poll_iE7221 }, - { 0x8086, 0x2770, "Intel i945P/G", 0, poll_fsb_i945, poll_timings_i925, setup_i925, poll_nothing }, - { 0x8086, 0x27A0, "Intel i945GM/PM", 0, poll_fsb_i945, poll_timings_i925, setup_i925, poll_nothing }, - { 0x8086, 0x27AC, "Intel i945GME", 0, poll_fsb_i945, poll_timings_i925, setup_i925, poll_nothing }, - { 0x8086, 0x2774, "Intel i955X", 0, poll_fsb_i945, poll_timings_i925, setup_i925, poll_nothing}, - { 0x8086, 0x277C, "Intel i975X", 0, poll_fsb_i975, poll_timings_i925, setup_i925, poll_nothing}, - { 0x8086, 0x2970, "Intel i946PL/GZ", 0, poll_fsb_i965, poll_timings_i965, setup_p35, poll_nothing}, - { 0x8086, 0x2990, "Intel Q963/Q965", 0, poll_fsb_i965, poll_timings_i965, setup_p35, poll_nothing}, - { 0x8086, 0x29A0, "Intel P965/G965", 0, poll_fsb_i965, poll_timings_i965, setup_p35, poll_nothing}, - { 0x8086, 0x2A00, "Intel GM965/GL960", 0, poll_fsb_im965, poll_timings_im965, setup_p35, poll_nothing}, - { 0x8086, 0x2A10, "Intel GME965/GLE960",0, poll_fsb_im965, poll_timings_im965, setup_p35, poll_nothing}, - { 0x8086, 0x2A40, "Intel PM/GM45/47", 0, poll_fsb_im965, poll_timings_im965, setup_p35, poll_nothing}, - { 0x8086, 0x29B0, "Intel Q35", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x29C0, "Intel P35/G33", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x29D0, "Intel Q33", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x29E0, "Intel X38/X48", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x29F0, "Intel 3200/3210", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x2E10, "Intel Q45/Q43", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x2E20, "Intel P45/G45", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x2E30, "Intel G41", 0, poll_fsb_i965, poll_timings_p35, setup_p35, poll_nothing}, - { 0x8086, 0x4001, "Intel 5400A", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, - { 0x8086, 0x4003, "Intel 5400B", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, - { 0x8086, 0x25D8, "Intel 5000P", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, - { 0x8086, 0x25D4, "Intel 5000V", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, - { 0x8086, 0x25C0, "Intel 5000X", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, - { 0x8086, 0x25D0, "Intel 5000Z", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, - { 0x8086, 0x5020, "Intel EP80579", 0, poll_fsb_p4, poll_timings_EP80579, setup_nothing, poll_nothing }, - { 0x8086, 0x8100, "Intel US15W", 0, poll_fsb_us15w, poll_timings_us15w, setup_nothing, poll_nothing}, - { 0x8086, 0x8101, "Intel UL11L/US15L", 0, poll_fsb_us15w, poll_timings_us15w, setup_nothing, poll_nothing}, - - /* Integrated Memory Controllers */ - { 0xFFFF, 0x0001, "Core IMC", 0, poll_fsb_nhm, poll_timings_nhm, setup_nhm, poll_nothing}, - { 0xFFFF, 0x0002, "Core IMC 32nm", 0, poll_fsb_nhm32, poll_timings_nhm, setup_nhm32, poll_nothing}, - { 0xFFFF, 0x0003, "Core IMC 32nm", 0, poll_fsb_wmr, poll_timings_wmr, setup_wmr, poll_nothing}, - { 0xFFFF, 0x0004, "SNB IMC 32nm", 0, poll_fsb_snb, poll_timings_snb, setup_wmr, poll_nothing}, - { 0xFFFF, 0x0100, "AMD K8 IMC", 0, poll_fsb_amd64, poll_timings_amd64, setup_amd64, poll_amd64 }, - { 0xFFFF, 0x0101, "AMD K10 IMC", 0, poll_fsb_k10, poll_timings_k10, setup_k10, poll_nothing }, - { 0xFFFF, 0x0102, "AMD APU IMC", 0, poll_fsb_k14, poll_timings_k14, setup_nothing, poll_nothing }, - - /* Fail Safe */ - { 0xFFFF, 0xFFFF, "", 0, poll_fsb_failsafe, poll_timings_nothing, setup_nothing, poll_nothing } + { 0x8086, 0x1130, "Intel i815","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x122d, "Intel i430FX","EDO DRAM",0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x1235, "Intel i430MX","EDO DRAM",0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x1237, "Intel i440FX","EDO DRAM",0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x1250, "Intel i430HX","EDO DRAM",0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x1A21, "Intel i840","RDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_i840, poll_nothing }, + { 0x8086, 0x1A30, "Intel i845","SDR/DDR", 0, poll_fsb_p4, poll_timings_nothing, setup_i845, poll_nothing }, + { 0x8086, 0x2560, "Intel i845E/G/PE/GE","", 0, poll_fsb_p4, poll_timings_nothing, setup_i845, poll_nothing }, + { 0x8086, 0x2500, "Intel i820","RDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_i820, poll_nothing }, + { 0x8086, 0x2530, "Intel i850","RDRAM", 0, poll_fsb_p4, poll_timings_nothing, setup_i850, poll_nothing }, + { 0x8086, 0x2531, "Intel i860","RDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_i860, poll_nothing }, + { 0x8086, 0x7030, "Intel i430VX","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x7100, "Intel i430TX","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x7120, "Intel i810","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x7122, "Intel i810","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x7124, "Intel i810E","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x7180, "Intel i440[LE]X","SDRAM",0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x7190, "Intel i440BX","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x7192, "Intel i440BX","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x71A0, "Intel i440GX","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_i440gx, poll_nothing }, + { 0x8086, 0x71A2, "Intel i440GX","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_i440gx, poll_nothing }, + { 0x8086, 0x84C5, "Intel i450GX","SDRAM", 0, poll_fsb_nothing, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x2540, "Intel E7500","DDR-SDRAM",0, poll_fsb_p4, poll_timings_E750x, setup_iE7xxx, poll_nothing }, + { 0x8086, 0x254C, "Intel E7501","DDR-SDRAM",0, poll_fsb_p4, poll_timings_E750x, setup_iE7xxx, poll_nothing }, + { 0x8086, 0x255d, "Intel E7205","DDR-SDRAM",0, poll_fsb_p4, poll_timings_nothing, setup_iE7xxx, poll_nothing }, + { 0x8086, 0x3592, "Intel E7320","DDR-SDRAM",0, poll_fsb_p4, poll_timings_E7520, setup_iE7520, poll_nothing }, + { 0x8086, 0x2588, "Intel E7221","DDR-SDRAM",0, poll_fsb_i925, poll_timings_i925, setup_i925, poll_nothing }, + { 0x8086, 0x3590, "Intel E7520","DDR-SDRAM",0, poll_fsb_p4, poll_timings_E7520, setup_iE7520, poll_nothing }, + { 0x8086, 0x2600, "Intel E8500","DDR-SDRAM",0, poll_fsb_p4, poll_timings_nothing, setup_nothing, poll_nothing }, + { 0x8086, 0x2570, "Intel i848/i865","", 0, poll_fsb_i875, poll_timings_i875, setup_i875, poll_nothing }, + { 0x8086, 0x2578, "Intel i875P","", 0, poll_fsb_i875, poll_timings_i875, setup_i875, poll_nothing }, + { 0x8086, 0x2550, "Intel E7505","DDR-SDRAM",0, poll_fsb_p4, poll_timings_nothing, setup_iE7xxx, poll_nothing }, + { 0x8086, 0x3580, "Intel i852P/i855G","", 0, poll_fsb_i855, poll_timings_i852, setup_nothing, poll_nothing }, + { 0x8086, 0x3340, "Intel i855PM","", 0, poll_fsb_i855, poll_timings_i855, setup_nothing, poll_nothing }, + { 0x8086, 0x2580, "Intel i915P/G","", 0, poll_fsb_i925, poll_timings_i925, setup_i925, poll_nothing }, + { 0x8086, 0x2590, "Intel i915PM/GM","", 0, poll_fsb_i925, poll_timings_i925, setup_i925, poll_nothing }, + { 0x8086, 0x2584, "Intel i925X/XE","", 0, poll_fsb_i925, poll_timings_i925, setup_i925, poll_nothing }, + { 0x8086, 0x2770, "Intel i945P/G","", 0, poll_fsb_i945, poll_timings_i925, setup_i925, poll_nothing }, + { 0x8086, 0x27A0, "Intel i945GM/PM","", 0, poll_fsb_i945, poll_timings_i925, setup_i925, poll_nothing }, + { 0x8086, 0x27AC, "Intel i945GME","", 0, poll_fsb_i945gme, poll_timings_i925, setup_i925, poll_nothing }, + { 0x8086, 0x2774, "Intel i955X","", 0, poll_fsb_i945, poll_timings_i925, setup_i925, poll_nothing}, + { 0x8086, 0x277C, "Intel i975X","", 0, poll_fsb_i975, poll_timings_i925, setup_i925, poll_nothing}, + { 0x8086, 0x2970, "Intel i946PL/GZ","", 0, poll_fsb_i965, poll_timings_i965, setup_p35, poll_nothing}, + { 0x8086, 0x2990, "Intel Q963/Q965","", 0, poll_fsb_i965, poll_timings_i965, setup_p35, poll_nothing}, + { 0x8086, 0x29A0, "Intel P965/G965","", 0, poll_fsb_i965, poll_timings_i965, setup_p35, poll_nothing}, + { 0x8086, 0x2A00, "Intel GM965/GL960","", 0, poll_fsb_im965, poll_timings_im965, setup_p35, poll_nothing}, + { 0x8086, 0x2A10, "Intel GME965/GLE960","", 0, poll_fsb_im965, poll_timings_im965, setup_p35, poll_nothing}, + { 0x8086, 0x2A40, "Intel PM/GM45/47","", 0, poll_fsb_im965, poll_timings_im965, setup_p35, poll_nothing}, + { 0x8086, 0x29B0, "Intel Q35","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x29C0, "Intel P35/G33","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x29D0, "Intel Q33","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x29E0, "Intel X38/X48","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x29F0, "Intel 3200/3210","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x2E10, "Intel Q45/Q43","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x2E20, "Intel P45/G45","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x2E30, "Intel G41","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0x8086, 0x4001, "Intel 5400A","", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, + { 0x8086, 0x4003, "Intel 5400B","", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, + { 0x8086, 0x25D8, "Intel 5000P","", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, + { 0x8086, 0x25D4, "Intel 5000V","", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, + { 0x8086, 0x25C0, "Intel 5000X","", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, + { 0x8086, 0x25D0, "Intel 5000Z","", 0, poll_fsb_5400, poll_timings_5400, setup_E5400, poll_nothing}, + { 0x8086, 0x5020, "Intel EP80579","", 0, poll_fsb_p4, poll_timings_EP80579, setup_nothing, poll_nothing }, + { 0x8086, 0x8100, "Intel US15W","", 0, poll_fsb_us15w, poll_timings_us15w, setup_nothing, poll_nothing}, + { 0x8086, 0x8101, "Intel UL11L/US15L","", 0, poll_fsb_us15w, poll_timings_us15w, setup_nothing, poll_nothing}, + + /* INTEL IMC (Integrated Memory Controllers) */ + { 0xFFFF, 0x0001, "Core IMC","", 0, poll_fsb_nhm, poll_timings_nhm, setup_nhm, poll_nothing}, + { 0xFFFF, 0x0002, "Core IMC","", 0, poll_fsb_nhm32, poll_timings_nhm, setup_nhm32, poll_nothing}, + { 0xFFFF, 0x0003, "Core IMC","", 0, poll_fsb_wmr, poll_timings_wmr, setup_wmr, poll_nothing}, + { 0xFFFF, 0x0004, "SNB IMC","", 0, poll_fsb_snb, poll_timings_snb, setup_wmr, poll_nothing}, + { 0xFFFF, 0x0005, "SNB-E IMC","", 0, poll_fsb_snbe, poll_timings_snbe, setup_wmr, poll_nothing}, + { 0xFFFF, 0x0006, "IVB IMC","", 0, poll_fsb_ivb, poll_timings_snb, setup_wmr, poll_nothing}, + { 0xFFFF, 0x0007, "HSW IMC","", 0, poll_fsb_ivb, poll_timings_hsw, setup_wmr, poll_nothing}, + { 0xFFFF, 0x0008, "PineView IMC","", 0, poll_fsb_p35, poll_timings_p35, setup_p35, poll_nothing}, + { 0xFFFF, 0x0009, "CedarTrail IMC","", 0, poll_fsb_ct, poll_timings_ct, setup_nothing, poll_nothing}, + + /* AMD IMC (Integrated Memory Controllers) */ + { 0xFFFF, 0x0100, "AMD K8 IMC","", 0, poll_fsb_amd64, poll_timings_amd64, setup_amd64, poll_nothing }, + { 0xFFFF, 0x0101, "AMD K10 IMC","", 0, poll_fsb_k10, poll_timings_k10, setup_k10, poll_nothing }, + { 0xFFFF, 0x0102, "AMD K12 IMC","", 0, poll_fsb_k12, poll_timings_k12, setup_apu, poll_nothing }, + { 0xFFFF, 0x0103, "AMD K14 IMC","", 0, poll_fsb_k14, poll_timings_k14, setup_apu, poll_nothing }, + { 0xFFFF, 0x0104, "AMD K15 IMC","", 0, poll_fsb_k15, poll_timings_k15, setup_apu, poll_nothing }, + { 0xFFFF, 0x0105, "AMD K16 IMC","", 0, poll_fsb_k16, poll_timings_k16, setup_apu, poll_nothing } }; static void print_memory_controller(void) { - /* Print memory controller info */ - - int d; - char *name; + /* Print memory controller info */ if (ctrl.index == 0) { return; } - /* Print the controller name */ - name = controllers[ctrl.index].name; - col = 10; - cprint(LINE_CPU+5, col, name); - /* Now figure out how much I just printed */ - while(name[col - 10] != '\0') { - col++; - } /* Now print the memory controller capabilities */ + /* cprint(LINE_CPU+5, col, " "); col++; if (ctrl.cap == ECC_UNKNOWN) { return; @@ -3642,15 +4078,16 @@ static void print_memory_controller(void) cprint(LINE_CPU+5, col +7, on?"+ ":"- "); col += 9; } - + */ + + + /* Print advanced caracteristics */ col2 = 0; - d = get_key(); - /* if F1 is pressed, disable advanced detection */ - if (d != 0x3B) { + controllers[ctrl.index].poll_fsb(); controllers[ctrl.index].poll_timings(); - } + } @@ -3658,7 +4095,6 @@ void find_controller(void) { unsigned long vendor; unsigned long device; - extern struct cpu_ident cpu_id; int i; int result; result = pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, PCI_VENDOR_ID, 2, &vendor); @@ -3666,10 +4102,12 @@ void find_controller(void) // Detect IMC by CPUID if(imc_type) { vendor = 0xFFFF; device = imc_type; } - if(fail_safe) { vendor = 0xFFFF; device = 0xFFFF; } - + if(v->fail_safe & 1) { vendor = 0xFFFF; device = 0xFFFF; } + + //hprint(11,0,vendor); hprint(11,10,device); + ctrl.index = 0; - if (result == 0) { + if (result == 0 || imc_type) { for(i = 1; i < sizeof(controllers)/sizeof(controllers[0]); i++) { if ((controllers[i].vendor == vendor) && (controllers[i].device == device)) { ctrl.index = i; @@ -3682,8 +4120,10 @@ void find_controller(void) /* Don't enable ECC polling by default unless it has * been well tested. */ - set_ecc_polling(-1); + //set_ecc_polling(-1); print_memory_controller(); + + if(imc_type) { print_dmi_startup_info(); } } @@ -3694,6 +4134,7 @@ void poll_errors(void) } } +/* void set_ecc_polling(int val) { int tested = controllers[ctrl.index].tested; @@ -3708,5 +4149,5 @@ void set_ecc_polling(int val) cprint(LINE_INFO, COL_ECC, "off"); } } - +*/ diff --git a/controller.h b/controller.h index ff5cb06..da64ef1 100644 --- a/controller.h +++ b/controller.h @@ -1,8 +1,23 @@ #ifndef MEMTEST_CONTROLLER_H #define MEMTEST_CONTROLLER_H +struct pci_memory_controller { + unsigned vendor; + unsigned device; + char *name; + char *ram_type; + int tested; + void (*poll_fsb)(void); + void (*poll_timings)(void); + void (*setup_ecc)(void); + void (*poll_errors)(void); +}; + void find_controller(void); void poll_errors(void); void set_ecc_polling(int val); +void coretemp(void); +extern struct pci_memory_controller controllers[]; + #endif /* MEMTEST_CONTROLLER_H */ @@ -4,255 +4,84 @@ * Implements CPUID querying functions * */ +#include "stdin.h" #include "cpuid.h" -cpuid_t cpuid_data0; -cpuid_t cpuid_data80; +struct cpu_ident cpu_id; -unsigned num_logical_cpus = 1; // number of logical cpus per physical package -unsigned num_cores_per_package = 1; // number of cores in each physical cpu package -unsigned num_hyper_threads_per_core = 1; // number of hyper-threads per core - -void -cpuid_get(unsigned n, cpuid_t *data) -{ - data->eax = n; - GET_CPUID(data->eax, data->ebx, data->ecx, data->edx); -} - - -/* cpuid_get_vendor_string --- - * - * This function gets the vendor string from the processor's cpuid instruction - * and passes it back to the caller in an easy to use structure. - */ -cpuid_vendor_string_t -cpuid_get_vendor_string(void) -{ - static cpuid_vendor_string_t v; - - /* Note: the string gets passed in EBX-EDX-ECX, not the intuitive order. */ - v.uint32_array[0] = cpuid_data0.ebx; - v.uint32_array[1] = cpuid_data0.edx; - v.uint32_array[2] = cpuid_data0.ecx; - v.char_array[CPUID_VENDOR_STR_LENGTH-1] = '\0'; - return v; -} - - -/* cpuid_get_version --- - * - * This function reads the processors version information using CPUID and puts - * it into a union for easy use by the caller. - */ -cpuid_version_t -cpuid_get_version(void) -{ - cpuid_version_t v; - uint32_t junkEBX = 0, junkECX = 0, junkEDX = 0; - v.flat = 0x1; - GET_CPUID(v.flat, junkEBX, junkECX, junkEDX); - return v; -} - - -cpuid_feature_flags_t -cpuid_get_feature_flags(void) -{ - cpuid_feature_flags_t f; - uint32_t junkEAX = 0x1, junkEBX = 0; - GET_CPUID(junkEAX, junkEBX, f.uint32_array[1], f.uint32_array[0]); - return f; -} - - -/* - *----------------------------------------------------------------------------- - * - * cpuid_get_ext_feature_flags -- - * - * Passes back the caller the extended feature flags supported by - * this CPU. This can be used, among other things, to determine if the - * processor supports long mode. - * - * Results: - * Returns TRUE if the processor supports the extended feature flags - * CPUID node, and FALSE otherwise. - * - * Side effects: - * Calls CPUID a couple of times. - * - *----------------------------------------------------------------------------- - */ - -bool -cpuid_get_ext_feature_flags(cpuid_ext_feature_flags_t *f) // OUT: Flags for this CPU -{ - uint32_t eax, ebx, ecx; - - if (cpuid_data80.eax < 0x80000001) { - // Extended feature flags not supported on this CPU - return FALSE; - } - eax = CPUID_EXTENDED_FEATURE; - GET_CPUID(eax, ebx, ecx, f->flat); - return TRUE; -} - -#define CHAR_TO_INT(a,b,c,d) ((a) + (b) * 0x100 + (c) * 0x10000 + (d) * 0x1000000) - -bool -cpuid_is_vendor_amd(void) -{ - return cpuid_data0.ebx == CHAR_TO_INT('A', 'u', 't', 'h') - && cpuid_data0.edx == CHAR_TO_INT('e', 'n', 't', 'i') - && cpuid_data0.ecx == CHAR_TO_INT('c', 'A', 'M', 'D'); -} - - -bool -cpuid_is_vendor_intel(void) -{ - return cpuid_data0.ebx == CHAR_TO_INT('G', 'e', 'n', 'u') - && cpuid_data0.edx == CHAR_TO_INT('i', 'n', 'e', 'I') - && cpuid_data0.ecx == CHAR_TO_INT('n', 't', 'e', 'l'); -} - - -/* - *----------------------------------------------------------------------------- - * - * cpuid_is_family_p4 -- - * - * Returns TRUE if the processor we're running on is an Intel processor - * of the P4 family. - * - * Results: - * The obvious. - * - *----------------------------------------------------------------------------- - */ - -bool -cpuid_is_family_p4(void) -{ - cpuid_version_t v = cpuid_get_version(); - - return cpuid_is_vendor_intel() && v.bits.family == CPUID_FAMILY_EXTENDED && - v.bits.extendedFamily == CPUID_EXTENDED_FAMILY_PENTIUM4; -} - - -/* - *----------------------------------------------------------------------------- - * - * cpuid_is_family_p6 -- - * - * Returns TRUE if the processor we're running on belongs to the P6 family. - * - * Results: - * The obvious. - * - *----------------------------------------------------------------------------- - */ - -bool -cpuid_is_family_p6(void) -{ - cpuid_version_t v = cpuid_get_version(); - - return cpuid_is_vendor_intel() && v.bits.family == CPUID_FAMILY_P6; -} - - -/* - *----------------------------------------------------------------------------- - * - * cpuid_is_family_opteron -- - * - * Returns TRUE if the processor we're running on belongs to the - * Opteron family. - * - *----------------------------------------------------------------------------- - */ - -bool -cpuid_is_family_opteron(void) +void get_cpuid() { - cpuid_version_t v = cpuid_get_version(); - return cpuid_is_vendor_amd() && CPUID_FAMILY_IS_OPTERON(v.flat); -} - - -/* - *----------------------------------------------------------------------------- - * - * cpuid_init -- - * - * Executes CPUID and caches values in cpuid_data0 abd cpuid_data80. - * - *----------------------------------------------------------------------------- - */ -void -cpuid_init(void) -{ - //bool htt = FALSE; - cpuid_t id1; - - /* First get the basic cpuid information on what the - * type of the processor is , i.e intel or amd etc - * and how much of extra cpuid information is available - * with the processor - */ - cpuid_data0.eax = 0; - GET_CPUID(cpuid_data0.eax, cpuid_data0.ebx, - cpuid_data0.ecx, cpuid_data0.edx); - - - /* Find out if hyper-threading is available and there is more than one - * logical processor. See section 7.6.3 in Intel IA-32 volume III. - */ - cpuid_get(1, &id1); + unsigned int *v, dummy[3]; + char *p, *q; + + /* Get max std cpuid & vendor ID */ + cpuid(0x0, &cpu_id.max_cpuid, &cpu_id.vend_id.uint32_array[0], + &cpu_id.vend_id.uint32_array[2], &cpu_id.vend_id.uint32_array[1]); + cpu_id.vend_id.char_array[11] = 0; + + /* Get processor family information & feature flags */ + if (cpu_id.max_cpuid >= 1) { + cpuid(0x00000001, &cpu_id.vers.flat, &cpu_id.info.flat, + &cpu_id.fid.uint32_array[1], &cpu_id.fid.uint32_array[0]); + } + + /* Get the digital thermal sensor & power management status bits */ + if(cpu_id.max_cpuid >= 6) { + cpuid(0x00000006, &cpu_id.dts_pmp, &dummy[0], &dummy[1], &dummy[2]); + } + + /* Get the max extended cpuid */ + cpuid(0x80000000, &cpu_id.max_xcpuid, &dummy[0], &dummy[1], &dummy[2]); + + /* Get extended feature flags, only save EDX */ + if (cpu_id.max_xcpuid >= 0x80000001) { + cpuid(0x80000001, &dummy[0], &dummy[1], + &dummy[2], &cpu_id.fid.uint32_array[2]); + } + + /* Get the brand ID */ + if (cpu_id.max_xcpuid >= 0x80000004) { + v = (unsigned int *)&cpu_id.brand_id; + cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); + cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]); + cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]); + cpu_id.brand_id.char_array[47] = 0; + } + /* + * Intel chips right-justify this string for some dumb reason; + * undo that brain damage: + */ + p = q = &cpu_id.brand_id.char_array[0]; + while (*p == ' ') + p++; + if (p != q) { + while (*p) + *q++ = *p++; + while (q <= &cpu_id.brand_id.char_array[48]) + *q++ = '\0'; /* Zero-pad the rest */ + } + + /* Get cache information */ + switch(cpu_id.vend_id.char_array[0]) { + case 'A': + /* AMD Processors */ + /* The cache information is only in ecx and edx so only save + * those registers */ + if (cpu_id.max_xcpuid >= 0x80000005) { + cpuid(0x80000005, &dummy[0], &dummy[1], + &cpu_id.cache_info.uint[0], &cpu_id.cache_info.uint[1]); + } + if (cpu_id.max_xcpuid >= 0x80000006) { + cpuid(0x80000006, &dummy[0], &dummy[1], + &cpu_id.cache_info.uint[2], &cpu_id.cache_info.uint[3]); + } + break; + case 'G': + /* Intel Processors, Need to do this in init.c */ + break; + } + + /* Turn off mon bit since monitor based spin wait may not be reliable */ + cpu_id.fid.bits.mon = 0; - if (cpuid_is_vendor_intel()) { - if (cpuid_is_family_p6()) { - // Extended CPUID features not supported on PIII - return; - } - if (cpuid_is_family_p4()) { - /* - * Multi-core processors have the HT feature bit set (even if they - * don't support HT). - * The number of HT is the total number, not per-core number. - * The number of cores is off by 1, i.e. single-core reports 0. - */ - //htt = id1.edx & CPUID_FEATURE_COMMON_ID1EDX_HT; - if (id1.edx & CPUID_FEATURE_COMMON_ID1EDX_HT) { - num_hyper_threads_per_core = (id1.ebx >> 16) & 0xff; - if (cpuid_max_func() >= 4) { - cpuid_t id4; - cpuid_get(4, &id4); - num_cores_per_package = ((id4.eax >> 26) & 0x3f) + 1; - num_hyper_threads_per_core /= num_cores_per_package; - } - } - } - } else if (cpuid_is_vendor_amd()) { - cpuid_data80.eax = 0x80000000; - GET_CPUID(cpuid_data80.eax, cpuid_data80.ebx, - cpuid_data80.ecx, cpuid_data80.edx); - if (cpuid_max_ext_func() >= 0x80000008) { - /* Number of cores is reported in extended function 0x80000008 - * For legacy multi-core support, AMD CPUs report the number of - * cores as hyper-threads. Adjust the numbers to reflect that there - * are no threads. - */ - cpuid_t id88; - cpuid_get(0x80000008, &id88); - num_cores_per_package = id88.ecx & 0xff; - num_hyper_threads_per_core = 1; - } - } else { - /* Unknown cpu type. we use the defaults */ - } } @@ -1,83 +1,76 @@ /* * cpuid.h -- - * * contains the data structures required for CPUID * implementation. - * */ -#ifndef _CPUID_H_ -#define _CPUID_H_ -#include "stdint.h" -#include "defs.h" -#include "smp.h" - -#define CPUID_EXTENDED_BASE 0x80000000 -#define CPUID_EXTENDED_FEATURE 0x80000001 -#define CPUID_EXTENDED_BRAND1 0x80000002 -#define CPUID_EXTENDED_BRAND2 0x80000003 -#define CPUID_EXTENDED_BRAND3 0x80000004 - #define CPUID_VENDOR_LENGTH 3 /* 3 GPRs hold vendor ID */ #define CPUID_VENDOR_STR_LENGTH (CPUID_VENDOR_LENGTH * sizeof(uint32_t) + 1) #define CPUID_BRAND_LENGTH 12 /* 12 GPRs hold vendor ID */ #define CPUID_BRAND_STR_LENGTH (CPUID_BRAND_LENGTH * sizeof(uint32_t) + 1) -#define CPUID_FAMILY(_eax) (((_eax) >> 8) & 0xf) -/* Intel CPU Family */ -#define CPUID_FAMILY_486 4 -#define CPUID_FAMILY_P5 5 -#define CPUID_FAMILY_P6 6 -#define CPUID_FAMILY_EXTENDED 15 - -#define CPUID_EXTENDED_FAMILY(_eax) (((_eax) >> 20) & 0xff) -#define CPUID_EXTENDED_FAMILY_PENTIUM4 0 -#define CPUID_EXTENDED_FAMILY_OPTERON 0 - - -#define CPUID_FAMILY_IS_OPTERON(_eax) \ - (CPUID_FAMILY(_eax) == CPUID_FAMILY_EXTENDED && \ - CPUID_EXTENDED_FAMILY(_eax) == CPUID_EXTENDED_FAMILY_OPTERON) -#define CPUID_FEATURE_COMMON_ID1EDX_HT 0x10000000 /* 28 */ +extern struct cpu_ident cpu_id; - -typedef struct { - uint32_t eax; - uint32_t ebx; - uint32_t ecx; - uint32_t edx; -} cpuid_t; - -/* cached CPUID data for CPUID(0) and CPUID(0x80000000) */ -extern cpuid_t cpuid_data0; -extern cpuid_t cpuid_data80; - - -static inline unsigned -cpuid_max_func() +static inline void __cpuid(unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) { - return cpuid_data0.eax; + /* ecx is often an input as well as an output. */ + asm volatile("\t" + "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx" + : "=a" (*eax), + "=D" (*ebx), + "=c" (*ecx), + "=d" (*edx) + : "0" (*eax), "2" (*ecx)); } +static inline void cpuid(unsigned int op, + unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) +{ + *eax = op; + *ecx = 0; + __cpuid(eax, ebx, ecx, edx); +} -static inline unsigned -cpuid_max_ext_func() +/* Some CPUID calls want 'count' to be placed in ecx */ +static inline void cpuid_count(unsigned int op, int count, + unsigned int *eax, unsigned int *ebx, + unsigned int *ecx, unsigned int *edx) { - return cpuid_data80.eax; + *eax = op; + *ecx = count; + __cpuid(eax, ebx, ecx, edx); } +/* Typedef for storing the Cache Information */ +typedef union { + unsigned char ch[48]; + uint32_t uint[12]; + struct { + uint32_t fill1:24; /* Bit 0 */ + uint32_t l1_i_sz:8; + uint32_t fill2:24; + uint32_t l1_d_sz:8; + uint32_t fill3:16; + uint32_t l2_sz:16; + uint32_t fill4:18; + uint32_t l3_sz:14; + uint32_t fill5[8]; + } amd; +} cpuid_cache_info_t; /* Typedef for storing the CPUID Vendor String */ typedef union { /* Note: the extra byte in the char array is for '\0'. */ - char char_array[CPUID_VENDOR_STR_LENGTH]; + char char_array[CPUID_VENDOR_STR_LENGTH]; uint32_t uint32_array[CPUID_VENDOR_LENGTH]; } cpuid_vendor_string_t; /* Typedef for storing the CPUID Brand String */ typedef union { /* Note: the extra byte in the char array is for '\0'. */ - char char_array[CPUID_BRAND_STR_LENGTH]; + char char_array[CPUID_BRAND_STR_LENGTH]; uint32_t uint32_array[CPUID_BRAND_LENGTH]; } cpuid_brand_string_t; @@ -109,20 +102,27 @@ typedef union { /* Typedef for storing CPUID Feature flags */ typedef union { - uint64_t flat; - uint32_t uint32_array[2]; + uint32_t flat; + struct { + uint32_t :1; + } bits; +} cpuid_custom_features; + +/* Typedef for storing CPUID Feature flags */ +typedef union { + uint32_t uint32_array[3]; struct { - uint32_t fpu:1; /* Bit 0 */ + uint32_t fpu:1; /* EDX feature flags, bit 0 */ uint32_t vme:1; uint32_t de:1; uint32_t pse:1; - uint32_t tsc:1; + uint32_t rdtsc:1; uint32_t msr:1; uint32_t pae:1; uint32_t mce:1; uint32_t cx8:1; uint32_t apic:1; - uint32_t reserved10:1; + uint32_t bit10:1; uint32_t sep:1; uint32_t mtrr:1; uint32_t pge:1; @@ -132,7 +132,7 @@ typedef union { uint32_t pse36:1; uint32_t psn:1; uint32_t cflush:1; - uint32_t reserved20:1; + uint32_t bit20:1; uint32_t ds:1; uint32_t acpi:1; uint32_t mmx:1; @@ -142,76 +142,55 @@ typedef union { uint32_t ss:1; uint32_t htt:1; uint32_t tm:1; - uint32_t reserved30:1; - uint32_t pbe:1; /* Bit 31 */ - uint32_t sse3:1; /* Bit 32 */ - uint32_t reserved3433:2; - uint32_t monitor:1; + uint32_t bit30:1; + uint32_t pbe:1; /* EDX feature flags, bit 31 */ + uint32_t sse3:1; /* ECX feature flags, bit 0 */ + uint32_t mulq:1; + uint32_t bit2:1; + uint32_t mon:1; uint32_t dscpl:1; - uint32_t reserved3937:3; - uint32_t tm2:1; - uint32_t reserved41:1; - uint32_t cnxtid:1; - uint32_t reserved4443:2; - uint32_t cmpxchg16b:1; - uint32_t reserved6346:18; /* Bit 63 */ + uint32_t vmx:1; + uint32_t smx:1; + uint32_t eist:1; + uint32_t tm2:1; + uint32_t bits_9_31:23; + uint32_t bits0_28:29; /* EDX extended feature flags, bit 0 */ + uint32_t lm:1; /* Long Mode */ + uint32_t bits_30_31:2; /* EDX extended feature flags, bit 32 */ } bits; } cpuid_feature_flags_t; -/* Feature flags returned by extended CPUID node function 8000_0001. */ -typedef union { - uint64_t flat; - uint32_t uint32_array[2]; - struct { - uint32_t fpu:1; /* Bit 0 */ - uint32_t vme:1; - uint32_t de:1; - uint32_t pse:1; - uint32_t tsc:1; - uint32_t msr:1; - uint32_t pae:1; - uint32_t mce:1; - uint32_t cx8:1; - uint32_t apic:1; - uint32_t reserved10:1; - uint32_t sep:1; - uint32_t mtrr:1; - uint32_t pge:1; - uint32_t mca:1; - uint32_t cmov:1; - uint32_t pat:1; - uint32_t pse36:1; - uint32_t reserved1918:2; - uint32_t nx:1; - uint32_t reserved21:1; - uint32_t mmxamd:1; - uint32_t mmx:1; - uint32_t fxsr:1; - uint32_t ffxsr:1; - uint32_t reserved26:1; - uint32_t rdtscp:1; - uint32_t reserved28:1; - uint32_t lm:1; - uint32_t threedeenowext:1; - uint32_t threedeenow:1; /* Bit 31 */ - uint32_t lahf:1; /* Bit 32 */ - uint32_t cmplegacy:1; - uint32_t reserved3534:2; - uint32_t cr8avail:1; - uint32_t reserved6337:27; /* Bit 63 */ - } bits; -} cpuid_ext_feature_flags_t; - -void cpuid_get(unsigned n, cpuid_t *data); -cpuid_vendor_string_t cpuid_get_vendor_string(void); -cpuid_version_t cpuid_get_version(void); -cpuid_feature_flags_t cpuid_get_feature_flags(void); -bool cpuid_get_ext_feature_flags(cpuid_ext_feature_flags_t *f); -bool cpuid_is_vendor_amd(void); -bool cpuid_is_vendor_intel(void); -bool cpuid_is_family_p6(void); -bool cpuid_is_family_p4(void); -bool cpuid_is_family_opteron(void); -void cpuid_init(void); - -#endif +/* An overall structure to cache all of the CPUID information */ +struct cpu_ident { + uint32_t max_cpuid; + uint32_t max_xcpuid; + uint32_t dts_pmp; + cpuid_version_t vers; + cpuid_proc_info_t info; + cpuid_feature_flags_t fid; + cpuid_vendor_string_t vend_id; + cpuid_brand_string_t brand_id; + cpuid_cache_info_t cache_info; + cpuid_custom_features custom; +}; + +struct cpuid4_eax { + uint32_t ctype:5; + uint32_t level:3; + uint32_t is_self_initializing:1; + uint32_t is_fully_associative:1; + uint32_t reserved:4; + uint32_t num_threads_sharing:12; + uint32_t num_cores_on_die:6; +}; + +struct cpuid4_ebx { + uint32_t coherency_line_size:12; + uint32_t physical_line_partition:10; + uint32_t ways_of_associativity:10; +}; + +struct cpuid4_ecx { + uint32_t number_of_sets:32; +}; + @@ -1,18 +1,19 @@ -/* defs.h - MemTest-86 assembler/compiler definitions +/* defs.h - MemTest-86 Version 3.3 + * assembler/compiler definitions * * Released under version 2 of the Gnu Public License. - * By Chris Brady, cbrady@sgi.com - */ + * By Chris Brady + */ #define SETUPSECS 4 /* Number of setup sectors */ /* * Caution!! There is magic in the build process. Read - * README.build-process before you change anything. + * README.build-process before you change anything. * Unlike earlier versions all of the settings are in defs.h * so the build process should be more robust. */ -#define LOW_TEST_ADR 0x00002000 /* Final adrs for test code */ +#define LOW_TEST_ADR 0x00010000 /* Final adrs for test code */ #define BOOTSEG 0x07c0 /* Segment adrs for inital boot */ #define INITSEG 0x9000 /* Segment adrs for relocated boot */ @@ -40,6 +40,43 @@ struct tstruct_header{ uint16_t handle; } __attribute__((packed)); +struct system_map { + struct tstruct_header header; + uint8_t manufacturer; + uint8_t productname; + uint8_t version; + uint8_t serialnumber; + uint8_t uuidbytes[16]; + uint8_t wut; +} __attribute__((packed)); + +struct cpu_map { + struct tstruct_header header; + uint8_t cpu_socket; + uint8_t cpu_type; + uint8_t cpu_family; + uint8_t cpu_manufacturer; + uint32_t cpu_id; + uint8_t cpu_version; + uint8_t cpu_voltage; + uint16_t ext_clock; + uint16_t max_speed; + uint16_t cur_speed; + uint8_t cpu_status; + uint8_t cpu_upgrade; + uint16_t l1_handle; + uint16_t l2_handle; + uint16_t l3_handle; + uint8_t cpu_serial; + uint8_t cpu_asset_tag; + uint8_t cpu_part_number; + uint8_t core_count; + uint8_t core_enabled; + uint8_t thread_count; + uint16_t cpu_specs; + uint16_t cpu_family_2; +} __attribute__((packed)); + struct mem_dev { struct tstruct_header header; uint16_t pma_handle; @@ -91,7 +128,7 @@ static char *form_factors[] = { static char *memory_types[] = { "?", - "Other", "Unknown", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM", + "Other", "????", "DRAM", "EDRAM", "VRAM", "SRAM", "RAM", "ROM", "FLASH", "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM", "DDR", "DDR2", "DDR2 FB", "RSVD", "RSVD","RSVD","DDR3","FBD2" @@ -101,17 +138,12 @@ static char *memory_types[] = { struct mem_dev * mem_devs[MAX_DMI_MEMDEVS]; int mem_devs_count=0; struct md_map * md_maps[MAX_DMI_MEMDEVS]; +struct system_map * dmi_system_info; +struct cpu_map * dmi_cpu_info; int md_maps_count=0; int dmi_err_cnts[MAX_DMI_MEMDEVS]; short dmi_initialized=0; -int strlen(char * string){ - int i=0; - while(*string++){i++;}; - return i; -} - - char * get_tstruct_string(struct tstruct_header *header, int n){ if(n<1) return 0; @@ -172,13 +204,28 @@ int open_dmi(void){ //look at all structs while(dmi < table_start + eps->tablelength){ struct tstruct_header *header = (struct tstruct_header *)dmi; + if (header->type == 17) - mem_devs[mem_devs_count++]=(struct mem_dev *)dmi; + mem_devs[mem_devs_count++] = (struct mem_dev *)dmi; // Need fix (SMBIOS/DDR3) if (header->type == 20 || header->type == 1) - md_maps[md_maps_count++]=(struct md_map *)dmi; + md_maps[md_maps_count++] = (struct md_map *)dmi; + + // MB_SPEC + if (header->type == 2) + { + dmi_system_info = (struct system_map *)dmi; + } + + // CPU_SPEC + if (header->type == 4) + { + dmi_cpu_info = (struct cpu_map *)dmi; + } + dmi+=header->length; + while( ! (*dmi == 0 && *(dmi+1) == 0 ) ) dmi++; dmi+=2; @@ -197,6 +244,46 @@ void init_dmi(void){ dmi_initialized=1; } +void print_dmi_startup_info(void) +{ + char *string1; + char *string2; + char *string3; + int dmicol = 78; + int slenght; + int sl1, sl2, sl3; + + if(!dmi_initialized) { init_dmi(); } + + string1 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->manufacturer); + sl1 = strlen(string1); + string2 = get_tstruct_string(&dmi_system_info->header,dmi_system_info->productname); + sl2 = strlen(string2); + string3 = get_tstruct_string(&dmi_cpu_info->header,dmi_cpu_info->cpu_socket); + sl3 = strlen(string3); + + slenght = sl1 + sl2; + if(sl3 > 2) { slenght += sl3 + 4; } else { slenght++; } + + if(sl1 && sl2) + { + //dmicol -= slenght; // right align + dmicol = 39 - slenght/2; // center align + cprint(LINE_DMI, dmicol, string1); + dmicol += sl1 + 1; + cprint(LINE_DMI, dmicol, string2); + dmicol += sl2 + 1; + + if(sl3 > 2){ + cprint(LINE_DMI, dmicol, "("); + dmicol++; + cprint(LINE_DMI, dmicol, string3); + dmicol += sl3; + cprint(LINE_DMI, dmicol, ")"); + } + } +} + void print_dmi_info(void){ int i,j,page; char * string=0; @@ -256,22 +343,30 @@ void print_dmi_info(void){ //print mappings int mapped=0,of=0; cprint(yof+1, POP2_X+6,"mapped to: "); - for(j=0; j<md_maps_count; j++){ + for(j=0; j<md_maps_count; j++) + { if (mem_devs[i]->header.handle != md_maps[j]->md_handle) continue; if (mapped++){ cprint(yof+1, POP2_X+17+of, ","); of++; } - hprint3(yof+1, POP2_X+17+of, md_maps[j]->start<<10, 12); - of += 12; + hprint3(yof+1, POP2_X+17+of, md_maps[j]->start>>22, 4); + of += 4; + hprint3(yof+1, POP2_X+17+of, md_maps[j]->start<<10, 8); + of += 8; cprint(yof+1, POP2_X+17+of, "-"); of++; - hprint3(yof+1, POP2_X+17+of, md_maps[j]->end<<10, 12); - of += 12; + hprint3(yof+1, POP2_X+17+of, md_maps[j]->end>>22, 4); + of += 4; + hprint3(yof+1, POP2_X+17+of, ((md_maps[j]->end+1)<<10) - 1, 8); + of += 8; + if(md_maps[j]->end == 0) { hprint3(yof+1, POP2_X+17+of-8,0,8); } } if (!mapped) + { cprint(yof+1, POP2_X+17, "No mapping (Interleaved Device)"); + } } @@ -3,4 +3,5 @@ int add_dmi_err(ulong adr); void print_dmi_err(void); void print_dmi_info(void); +void print_dmi_startup_info(void); #endif @@ -14,7 +14,7 @@ #define EM_NONE 0 /* No machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SUN SPARC */ -#define EM_386 3 /* Intel 80386+*/ +#define EM_386 3 /* Intel 80386+ */ #define EM_68K 4 /* Motorola m68k family */ #define EM_88K 5 /* Motorola m88k family */ #define EM_486 6 /* Perhaps disused */ @@ -61,7 +61,7 @@ #define EM_PDSP 63 /* Sony DSP Processor */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ -#define EM_ST9PLUS 67 /* STMicroelectronics ST9+8/16 mc */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ #define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ @@ -145,8 +145,8 @@ #include "stdint.h" /* -* ELF definitions common to all 32-bit architectures. -*/ + * ELF definitions common to all 32-bit architectures. + */ typedef uint32_t Elf32_Addr; typedef uint16_t Elf32_Half; @@ -167,8 +167,8 @@ typedef uint64_t Elf64_Xword; typedef int64_t Elf64_Sxword; /* -* ELF header. -*/ + * ELF header. + */ typedef struct { unsigned char e_ident[EI_NIDENT]; /* File identification. */ Elf32_Half e_type; /* File type. */ @@ -204,8 +204,8 @@ typedef struct { } Elf64_Ehdr; /* -* Program header. -*/ + * Program header. + */ typedef struct { Elf32_Word p_type; /* Entry type. */ Elf32_Off p_offset; /* File offset of contents. */ @@ -295,8 +295,8 @@ typedef struct #define DT_PROCNUM 0x32 /* Most used by any processor */ /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the - Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's - approach. */ + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ #define DT_VALRNGLO 0x6ffffd00 #define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ #define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ @@ -315,10 +315,10 @@ typedef struct #define DT_VALNUM 12 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the - Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. - If any adjustment is made to the ELF object after it has been - built these entries will need to be adjusted. */ + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 #define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ #define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ @@ -333,7 +333,7 @@ typedef struct #define DT_ADDRNUM 10 /* The versioning entry types. The next are defined as part of the - GNU extension. */ + GNU extension. */ #define DT_VERSYM 0x6ffffff0 #define DT_RELACOUNT 0x6ffffff9 @@ -351,7 +351,7 @@ typedef struct #define DT_VERSIONTAGNUM 16 /* Sun added these machine-independent extensions in the "processor-specific" - range. Be compatible. */ + range. Be compatible. */ #define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ #define DT_FILTER 0x7fffffff /* Shared object to get values from */ #define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) @@ -365,7 +365,7 @@ typedef struct #define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ /* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 - entry in the dynamic section. */ + entry in the dynamic section. */ #define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ #define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ #define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ @@ -493,8 +493,8 @@ typedef struct } Elf32_Rel; /* I have seen two different definitions of the Elf64_Rel and - Elf64_Rela structures, so we'll leave them out until Novell (or - whoever) gets their act together. */ + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ /* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ typedef struct @@ -523,11 +523,11 @@ typedef struct #define ELF32_R_SYM(val) ((val) >> 8) #define ELF32_R_TYPE(val) ((val) & 0xff) -#define ELF32_R_INFO(sym, type) (((sym) << 8) +((type) & 0xff)) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i) & 0xffffffff) -#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) +(type)) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) /* Intel 80386 specific definitions. */ @@ -581,7 +581,8 @@ typedef struct TLS block */ #define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ #define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ -#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block *//* Keep this the last entry. */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ #define R_386_NUM 38 #endif /* ASSEMBLY */ @@ -1,42 +1,151 @@ - -/* error.c - MemTest-86 Version 3.4 +/* error.c - MemTest-86 Version 4.1 * * Released under version 2 of the Gnu Public License. - * By Chris Brady, cbrady@sgi.com - * ---------------------------------------------------- - * MemTest86+ V4.00 Specific code (GPL V2.0) - * By Samuel DEMEULEMEESTER, sdemeule@memtest.org - * http://www.canardpc.com - http://www.memtest.org + * By Chris Brady */ - +#include "stddef.h" +#include "stdint.h" #include "test.h" #include "config.h" -#include <sys/io.h> +#include "cpuid.h" +#include "smp.h" #include "dmi.h" -#define NULL 0 +#include "controller.h" -extern int test_ticks, nticks, beepmode; -extern struct tseq tseq[]; extern int dmi_err_cnts[MAX_DMI_MEMDEVS]; +extern int beepmode; extern short dmi_initialized; +extern struct cpu_ident cpu_id; +extern struct barrier_s *barr; +extern int test_ticks, nticks; +extern struct tseq tseq[]; +extern volatile int test; void poll_errors(); +extern int num_cpus; static void update_err_counts(void); static void print_err_counts(void); +static void common_err(); static int syn, chan, len=1; /* + * Display data error message. Don't display duplicate errors. + */ +void error(ulong *adr, ulong good, ulong bad) +{ + + ulong xor; + + spin_lock(&barr->mutex); + + xor = good ^ bad; + +#ifdef USB_WAR + /* Skip any errrors that appear to be due to the BIOS using location + * 0x4e0 for USB keyboard support. This often happens with Intel + * 810, 815 and 820 chipsets. It is possible that we will skip + * a real error but the odds are very low. + */ + if ((ulong)adr == 0x4e0 || (ulong)adr == 0x410) { + return; + } +#endif + + /* A sporadic bug exists in test #6, with SMP enabled, that + * reports false positives on < 65K-0.5MB range. I was + * not able to solve this. After investigations, it seems + * related to a BIOS issue similiar to the one solved by + * USB_WAR, but for MP Table. + */ + /* Solved + if (test == 6 && (ulong)adr <= 0x07FFFF && num_cpus > 1) + { + cprint(6,78,"-"); // Debug + return; + } + */ + + common_err(adr, good, bad, xor, 0); + spin_unlock(&barr->mutex); +} + + + +/* + * Display address error message. + * Since this is strictly an address test, trying to create BadRAM + * patterns does not make sense. Just report the error. + */ +void ad_err1(ulong *adr1, ulong *mask, ulong bad, ulong good) +{ + spin_lock(&barr->mutex); + common_err(adr1, good, bad, (ulong)mask, 1); + spin_unlock(&barr->mutex); +} + +/* + * Display address error message. + * Since this type of address error can also report data errors go + * ahead and generate BadRAM patterns. + */ +void ad_err2(ulong *adr, ulong bad) +{ + spin_lock(&barr->mutex); + common_err(adr, (ulong)adr, bad, ((ulong)adr) ^ bad, 0); + spin_unlock(&barr->mutex); +} + +static void update_err_counts(void) +{ + if (beepmode){ + beep(600); + beep(1000); + } + + if (v->pass && v->ecount == 0) { + cprint(LINE_MSG, COL_MSG, + " "); + } + ++(v->ecount); + tseq[test].errors++; + +} + +static void print_err_counts(void) +{ + int i; + char *pp; + + if ((v->ecount > 4096) && (v->ecount % 256 != 0)) return; + + dprint(LINE_INFO, 72, v->ecount, 6, 0); +/* + dprint(LINE_INFO, 56, v->ecc_ecount, 6, 0); +*/ + + /* Paint the error messages on the screen red to provide a vivid */ + /* indicator that an error has occured */ + if ((v->printmode == PRINTMODE_ADDRESSES || + v->printmode == PRINTMODE_PATTERNS) && + v->msg_line < 24) { + for(i=0, pp=(char *)((SCREEN_ADR+v->msg_line*160+1)); + i<76; i++, pp+=2) { + *pp = 0x47; + } + } +} + +/* * Print an individual error */ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) { - int i, n, x, j, flag=0; + int i, j, n, x, flag=0; ulong page, offset; int patnchg; ulong mb; update_err_counts(); - add_dmi_err((ulong)adr); switch(v->printmode) { case PRINTMODE_SUMMARY: @@ -124,8 +233,6 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) cprint(LINE_HEADER+4, 1, " Bits in Error - Total:"); cprint(LINE_HEADER+4, 29, "Min: Max: Avg:"); cprint(LINE_HEADER+5, 1, " Max Contiguous Errors:"); - cprint(LINE_HEADER+6, 1, "ECC Correctable Errors:"); - cprint(LINE_HEADER+7, 1, "Errors per Memory Slot:"); x = 24; if (dmi_initialized) { for ( i=0; i < MAX_DMI_MEMDEVS;){ @@ -141,7 +248,7 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) x += 10; } } - + cprint(LINE_HEADER+0, 64, "Test Errors"); v->erri.hdr_flag++; } @@ -159,7 +266,7 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) hprint2(LINE_HEADER+1, 33, offset, 3); cprint(LINE_HEADER+1, 36, " - . MB"); dprint(LINE_HEADER+1, 39, mb, 5, 0); - dprint(LINE_HEADER+1, 45, ((page & 0xFF)*10)/256, 1, 0); + dprint(LINE_HEADER+1, 45, ((page & 0xF)*10)/16, 1, 0); page = v->erri.high_addr.page; offset = v->erri.high_addr.offset; mb = page >> 8; @@ -167,7 +274,7 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) hprint2(LINE_HEADER+2, 33, offset, 3); cprint(LINE_HEADER+2, 36, " - . MB"); dprint(LINE_HEADER+2, 39, mb, 5, 0); - dprint(LINE_HEADER+2, 45, ((page & 0xFF)*10)/256, 1, 0); + dprint(LINE_HEADER+2, 45, ((page & 0xF)*10)/16, 1, 0); hprint(LINE_HEADER+3, 25, v->erri.ebits); dprint(LINE_HEADER+4, 25, n, 2, 1); dprint(LINE_HEADER+4, 34, v->erri.min_bits, 2, 1); @@ -186,7 +293,7 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) } x += 10; } - + for (i=0; tseq[i].msg != NULL; i++) { dprint(LINE_HEADER+1+i, 66, i, 2, 0); dprint(LINE_HEADER+1+i, 68, tseq[i].errors, 8, 0); @@ -206,7 +313,7 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) if (v->erri.hdr_flag == 0) { clear_scroll(); cprint(LINE_HEADER, 0, -"Tst Pass Failing Address Good Bad Err-Bits Count Chan"); +"Tst Pass Failing Address Good Bad Err-Bits Count CPU"); cprint(LINE_HEADER+1, 0, "--- ---- ----------------------- -------- -------- -------- ----- ----"); v->erri.hdr_flag++; @@ -223,13 +330,13 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) offset = ((unsigned long)adr) & 0xFFF; } mb = page >> 8; - dprint(v->msg_line, 0, v->test, 3, 0); + dprint(v->msg_line, 0, test+1, 3, 0); dprint(v->msg_line, 4, v->pass, 5, 0); hprint(v->msg_line, 11, page); hprint2(v->msg_line, 19, offset, 3); cprint(v->msg_line, 22, " - . MB"); dprint(v->msg_line, 25, mb, 5, 0); - dprint(v->msg_line, 31, ((page & 0xFF)*10)/256, 1, 0); + dprint(v->msg_line, 31, ((page & 0xF)*10)/16, 1, 0); if (type == 3) { /* ECC error */ @@ -245,6 +352,7 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) hprint(v->msg_line, 46, bad); hprint(v->msg_line, 56, xor); dprint(v->msg_line, 66, v->ecount, 5, 0); + dprint(v->msg_line, 74, smp_my_cpu_num(), 2,1); v->erri.exor = xor; } v->erri.eadr = (ulong)adr; @@ -257,7 +365,7 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) v->erri.hdr_flag++; } /* Do not do badram patterns from test 0 or 5 */ - if (v->test == 0 || v->test == 5) { + if (test == 0 || test == 5) { return; } /* Only do patterns for data errors */ @@ -281,86 +389,6 @@ void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type) } /* - * Display data error message. Don't display duplicate errors. - */ -void error(ulong *adr, ulong good, ulong bad) -{ - ulong xor; - - xor = good ^ bad; -#ifdef USB_WAR - /* Skip any errrors that appear to be due to the BIOS using location - * 0x4e0 for USB keyboard support. This often happens with Intel - * 810, 815 and 820 chipsets. It is possible that we will skip - * a real error but the odds are very low. - */ - if ((ulong)adr == 0x4e0 || (ulong)adr == 0x410) { - return; - } -#endif - common_err(adr, good, bad, xor, 0); -} - -/* - * Display address error message. - * Since this is strictly an address test, trying to create BadRAM - * patterns does not make sense. Just report the error. - */ -void ad_err1(ulong *adr1, ulong *mask, ulong bad, ulong good) -{ - common_err(adr1, good, bad, (ulong)mask, 1); -} - -/* - * Display address error message. - * Since this type of address error can also report data errors go - * ahead and generate BadRAM patterns. - */ -void ad_err2(ulong *adr, ulong bad) -{ - common_err(adr, (ulong)adr, bad, ((ulong)adr) ^ bad, 0); -} - -static void update_err_counts(void) -{ - if (beepmode){ - beep(600); - beep(1000); - } - - if (v->pass && v->ecount == 0) { - cprint(LINE_MSG, COL_MSG, - " "); - } - ++(v->ecount); - tseq[v->test].errors++; - -} - -static void print_err_counts(void) -{ - int i; - char *pp; - - if ((v->ecount > 4096) && (v->ecount % 256 != 0)) return; - - dprint(LINE_INFO, COL_ERR, v->ecount, 6, 0); - dprint(LINE_INFO, COL_ECC_ERR, v->ecc_ecount, 6, 0); - - /* Paint the error messages on the screen red to provide a vivid */ - /* indicator that an error has occured */ - if ((v->printmode == PRINTMODE_ADDRESSES || - v->printmode == PRINTMODE_PATTERNS) && - v->msg_line < 24) { - for(i=0, pp=(char *)((SCREEN_ADR+v->msg_line*160+1)); - i<76; i++, pp+=2) { - *pp = 0x47; - } - } -} - - -/* * Print an ecc error */ void print_ecc_err(unsigned long page, unsigned long offset, @@ -380,7 +408,7 @@ void parity_err( unsigned long edi, unsigned long esi) { unsigned long addr; - if (v->test == 5) { + if (test == 5) { addr = esi; } else { addr = edi; @@ -427,10 +455,33 @@ void printpatn (void) /* * Show progress by displaying elapsed time and update bar graphs */ -void do_tick(void) +short spin_idx[MAX_CPUS]; +char spin[4] = {'|','/','-','\\'}; + +void do_tick(int me) { - int i, n, pct; - ulong h, l, t; + int i, j, pct; + ulong h, l, n, t; + extern int mstr_cpu; + + if (++spin_idx[me] > 3) { + spin_idx[me] = 0; + } + cplace(8, me+7, spin[spin_idx[me]]); + + + /* Check for keyboard input */ + if (me == mstr_cpu) { + check_input(); + } + /* A barrier here holds the other CPUs until the configuration + * changes are done */ + s_barrier(); + + /* Only the first selected CPU does the update */ + if (me != mstr_cpu) { + return; + } /* FIXME only print serial error messages from the tick handler */ if (v->ecount) { @@ -448,30 +499,31 @@ void do_tick(void) } else { pct = 0; } - - dprint(1, COL_MID+4, pct, 3, 0); + dprint(2, COL_MID+4, pct, 3, 0); i = (BAR_SIZE * pct) / 100; while (i > v->tptr) { if (v->tptr >= BAR_SIZE) { break; } - cprint(1, COL_MID+9+v->tptr, "#"); + cprint(2, COL_MID+9+v->tptr, "#"); v->tptr++; } if (v->pass_ticks) { pct = 100*v->total_ticks/v->pass_ticks; - if (pct > 100) { pct = 100; } + if (pct > 100) { + pct = 100; + } } else { pct = 0; - } - dprint(0, COL_MID+4, pct, 3, 0); + } + dprint(1, COL_MID+4, pct, 3, 0); i = (BAR_SIZE * pct) / 100; while (i > v->pptr) { if (v->pptr >= BAR_SIZE) { break; } - cprint(0, COL_MID+9+v->pptr, "#"); + cprint(1, COL_MID+9+v->pptr, "#"); v->pptr++; } @@ -495,7 +547,7 @@ void do_tick(void) } pct += n*3; } else { - for (i=0, n=0; i<v->test; i++) { + for (i=0, n=0; i<test; i++) { if (tseq[i].errors == 0) { n++; } @@ -530,7 +582,7 @@ void do_tick(void) /* We can't do the elapsed time unless the rdtsc instruction * is supported */ - if (v->rdtsc) { + if (cpu_id.fid.bits.rdtsc) { asm __volatile__( "rdtsc":"=a" (l),"=d" (h)); asm __volatile__ ( @@ -542,20 +594,34 @@ void do_tick(void) t = h * ((unsigned)0xffffffff / v->clks_msec) / 1000; t += (l / v->clks_msec) / 1000; i = t % 60; - dprint(LINE_TIME, COL_TIME+9, i%10, 1, 0); - dprint(LINE_TIME, COL_TIME+8, i/10, 1, 0); - t /= 60; - i = t % 60; - dprint(LINE_TIME, COL_TIME+6, i % 10, 1, 0); - dprint(LINE_TIME, COL_TIME+5, i / 10, 1, 0); - t /= 60; - dprint(LINE_TIME, COL_TIME, t, 4, 0); + j = i % 10; + + if(j != v->each_sec) + { + + dprint(LINE_TIME, COL_TIME+9, i % 10, 1, 0); + dprint(LINE_TIME, COL_TIME+8, i / 10, 1, 0); + t /= 60; + i = t % 60; + dprint(LINE_TIME, COL_TIME+6, i % 10, 1, 0); + dprint(LINE_TIME, COL_TIME+5, i / 10, 1, 0); + t /= 60; + dprint(LINE_TIME, COL_TIME, t, 4, 0); + + if(v->check_temp > 0 && !(v->fail_safe & 4)) + { + coretemp(); + } + v->each_sec = j; + } + } + - /* Check for keyboard input */ - check_input(); - /* Poll for ECC errors */ +/* poll_errors(); +*/ } + @@ -12,7 +12,6 @@ #include "pci.h" #include "extra.h" -static int claim = 0; static int ctrl = -1; struct memory_controller { @@ -429,7 +428,6 @@ void get_menu(void) int menu ; find_memctr(); - disclaimer(); switch(ctrl) { @@ -537,35 +535,6 @@ int get_cas(void) return (cas); } -void disclaimer(void) -{ - if ((ctrl == -1) || ( ctrl > sizeof(mem_ctr)/sizeof(mem_ctr[0]))) - { - popclear(); - wait_keyup(); - cprint(POP_Y+3, POP_X+4, " Chipset "); - cprint(POP_Y+4, POP_X+4, "Not supported !"); - get_key(); - wait_keyup(); - popclear(); - } - else if (claim == 0) - { - ulong j = 0; - - while (j<500000) - { - cprint(POP_Y+1, POP_X+3, "Disclaimer : "); - cprint(POP_Y+3, POP_X+3, "Modifying timing may "); - cprint(POP_Y+4, POP_X+3, "cause system instability"); - cprint(POP_Y+5, POP_X+3, "proceed at your own risk"); - j++; - } - claim = 1; - popclear(); - } -} - ///////////////////////////////////////////////////////// // here we go for the exciting timing change part... // ///////////////////////////////////////////////////////// @@ -17,48 +17,17 @@ #include "config.h" #include "test.h" -/* - * References to members of the boot_cpu_data structure. - */ -#define CPU_PARAMS cpu_id -#define X86 0 -#define X86_MODEL 1 -#define X86_MASK 2 -#define X86_CPUID 4 -#define X86_CAPABILITY 8 -#define X86_VENDOR_ID 12 -#define X86_CACHE 24 -#define X86_PWRCAP 40 -#define X86_EXT 44 -#define X86_FFL 48 -#define X86_DCACHE0_EAX 52 -#define X86_DCACHE0_EBX 56 -#define X86_DCACHE0_ECX 60 -#define X86_DCACHE0_EDX 64 -#define X86_DCACHE1_EAX 68 -#define X86_DCACHE1_EBX 72 -#define X86_DCACHE1_ECX 76 -#define X86_DCACHE1_EDX 80 -#define X86_DCACHE2_EAX 84 -#define X86_DCACHE2_EBX 88 -#define X86_DCACHE2_ECX 92 -#define X86_DCACHE2_EDX 96 -#define X86_DCACHE3_EAX 100 -#define X86_DCACHE3_EBX 104 -#define X86_DCACHE3_ECX 108 -#define X86_DCACHE3_EDX 112 - .code32 .globl startup_32 startup_32: cld cli - /* Ensure I have a stack pointer */ + /* Ensure I have a boot_stack pointer */ testl %esp, %esp jnz 0f movl $(LOW_TEST_ADR + _GLOBAL_OFFSET_TABLE_), %esp - leal stack_top@GOTOFF(%esp), %esp + leal boot_stack_top@GOTOFF(%esp), %esp 0: /* Load the GOT pointer */ @@ -66,8 +35,8 @@ startup_32: 0: popl %ebx addl $_GLOBAL_OFFSET_TABLE_+[.-0b], %ebx - /* Pick the appropriate stack address */ - leal stack_top@GOTOFF(%ebx), %esp + /* Pick the appropriate boot_stack address */ + leal boot_stack_top@GOTOFF(%ebx), %esp /* Reload all of the segment registers */ leal gdt@GOTOFF(%ebx), %eax @@ -101,23 +70,7 @@ flush: movl $KERNEL_DS, %eax zerobss_done: /* - * Clear the video display - */ - cmpl $1, clear_display@GOTOFF(%ebx) - jnz clear_display_done - movw $0x0720, %ax - movl $0xb8000, %edi - movl $0xc0000, %ecx -1: movw %ax, (%edi) - addl $2, %edi - cmpl %ecx, %edi - jnz 1b - movl $0, clear_display@GOTOFF(%ebx) -clear_display_done: - - -/* - * Setup and exception handler + * Setup an exception handler */ leal idt@GOTOFF(%ebx), %edi @@ -286,216 +239,14 @@ clear_display_done: movl %eax, 2 + idt_descr@GOTOFF(%ebx) lidt idt_descr@GOTOFF(%ebx) -/* Find out the CPU type */ - - leal cpu_id@GOTOFF(%ebx), %esi - movl %ebx, %edi - - movl $-1, X86_CPUID(%esi) # -1 for no CPUID initially - -/* check if it is 486 or 386. */ - - movl $3, X86(%esi) # at least 386 - pushfl # push EFLAGS - popl %eax # get EFLAGS - movl %eax, %ecx # save original EFLAGS - xorl $0x40000, %eax # flip AC bit in EFLAGS - pushl %eax # copy to EFLAGS - popfl # set EFLAGS - pushfl # get new EFLAGS - popl %eax # put it in eax - xorl %ecx, %eax # change in flags - andl $0x40000, %eax # check if AC bit changed - je id_done - - movl $4, X86(%esi) # at least 486 - movl %ecx, %eax - xorl $0x200000, %eax # check ID flag - pushl %eax - popfl # if we are on a straight 486DX, SX, or - pushfl # 487SX we can't change it - popl %eax - xorl %ecx, %eax - pushl %ecx # restore original EFLAGS - popfl - andl $0x200000, %eax - jne have_cpuid - - /* Test for Cyrix CPU types */ - xorw %ax, %ax # clear ax - sahf # clear flags - movw $5, %ax - movw $2, %bx - div %bl # do operation that does not change flags - lahf # get flags - cmp $2, %ah # check for change in flags - jne id_done # if not Cyrix - movl $2, X86(%esi) # Use two to identify as Cyrix - jmp id_done - -have_cpuid: - /* get vendor info */ - xorl %eax, %eax # call CPUID with 0 -> return vendor ID - cpuid - movl %eax, X86_CPUID(%esi) # save CPUID level - movl %ebx, X86_VENDOR_ID(%esi) # first 4 chars - movl %edx, X86_VENDOR_ID+4(%esi) # next 4 chars - movl %ecx, X86_VENDOR_ID+8(%esi) # last 4 chars - - orl %eax, %eax # do we have processor info as well? - je id_done - - movl $1, %eax # Use the CPUID instruction to get CPU type - cpuid - + leal _dl_start@GOTOFF(%ebx), %eax + call *%eax - # - # CDH start - # Check FPU, initialize if present - # - testl $1, %edx # FPU available? - jz no_fpu + /* Never forget to initialize the FPU ... Never ! */ finit - no_fpu: - # - # CDH end - # - - movl %eax, X86_EXT(%esi) # save complete extended CPUID to X86_EXT - movl %ecx, X86_FFL(%esi) # save ECX Feature Flags to X86_FFL - movb %al, %cl # save reg for future use - andb $0x0f, %ah # mask processor family - movb %ah, X86(%esi) - andb $0xf0, %al # mask model - shrb $4, %al - movb %al, X86_MODEL(%esi) - andb $0x0f, %cl # mask mask revision - movb %cl, X86_MASK(%esi) - movl %edx, X86_CAPABILITY(%esi) - - movl $0, X86_CACHE(%esi) - movl $0, X86_CACHE+4(%esi) - movl $0, X86_CACHE+8(%esi) - movl $0, X86_CACHE+12(%esi) - - movl X86_VENDOR_ID+8(%esi), %eax - cmpl $0x6c65746e,%eax # Is this an Intel CPU? "GenuineIntel" - jne not_intel - movb %bl, X86_PWRCAP(%esi) # Store BrandID in AMD PWRCAP if the CPU is from Intel - movl $2, %eax # Use the CPUID instruction to get cache info - cpuid - movl %eax, X86_CACHE(%esi) - movl %ebx, X86_CACHE+4(%esi) - movl %ecx, X86_CACHE+8(%esi) - movl %edx, X86_CACHE+12(%esi) -# Grab deterministic cache information (for 32nm Intel CPU) - cmpw $0x0000,%dx - jne id_done - movl $4, %eax - movl $0, %ecx - cpuid - movl %eax, X86_DCACHE0_EAX(%esi) - movl %ebx, X86_DCACHE0_EBX(%esi) - movl %ecx, X86_DCACHE0_ECX(%esi) - movl %edx, X86_DCACHE0_EDX(%esi) - movl $4, %eax - movl $1, %ecx - cpuid - movl %eax, X86_DCACHE1_EAX(%esi) - movl %ebx, X86_DCACHE1_EBX(%esi) - movl %ecx, X86_DCACHE1_ECX(%esi) - movl %edx, X86_DCACHE1_EDX(%esi) - movl $4, %eax - movl $2, %ecx - cpuid - movl %eax, X86_DCACHE2_EAX(%esi) - movl %ebx, X86_DCACHE2_EBX(%esi) - movl %ecx, X86_DCACHE2_ECX(%esi) - movl %edx, X86_DCACHE2_EDX(%esi) - movl $4, %eax - movl $3, %ecx - cpuid - movl %eax, X86_DCACHE3_EAX(%esi) - movl %ebx, X86_DCACHE3_EBX(%esi) - movl %ecx, X86_DCACHE3_ECX(%esi) - movl %edx, X86_DCACHE3_EDX(%esi) - jmp id_done - -not_intel: - movl X86_VENDOR_ID+8(%esi),%eax - cmpl $0x444d4163, %eax # Is this an AMD CPU? "AuthenticAMD" - jne not_amd - - movl $0x80000005, %eax # Use the CPUID instruction to get cache info - cpuid - movl %ecx, X86_CACHE(%esi) - movl %edx, X86_CACHE+4(%esi) - movl $0x80000006,%eax # Use the CPUID instruction to get cache info - cpuid - movl %ecx,X86_CACHE+8(%esi) - movl %edx,X86_CACHE+12(%esi) - movl $0x80000007,%eax # Use the CPUID instruction to get AMD Powercap - cpuid - movl %edx,X86_PWRCAP(%esi) - -not_amd: - movl X86_VENDOR_ID+8(%esi), %eax - cmpl $0x3638784D, %eax # Is this a Transmeta CPU? "GenuineTMx86" - jne not_transmeta - - movl $0x80000000, %eax # Use the CPUID instruction to check for cache info - cpuid - cmp $6, %al # Is cache info available? - jb id_done - - movl $0x80000005, %eax # Use the CPUID instruction to get L1 cache info - cpuid - movl %ecx, X86_CACHE(%esi) - movl %edx, X86_CACHE+4(%esi) - movl $0x80000006, %eax # Use the CPUID instruction to get L2 cache info - cpuid - movl %ecx, X86_CACHE+8(%esi) - -not_transmeta: - movl X86_VENDOR_ID+8(%esi), %eax - cmpl $0x64616574, %eax # Is this a Via/Cyrix CPU? "CyrixInstead" - jne not_cyrix - - movl X86_CPUID(%esi), %eax # get CPUID level - cmpl $2, %eax # Is there cache information available ? - jne id_done - - movl $2, %eax # Use the CPUID instruction to get cache info - cpuid - movl %edx, X86_CACHE(%esi) - -not_cyrix: - movl X86_VENDOR_ID+8(%esi), %eax - cmpl $0x736C7561, %eax # Is this a Via/Centaur CPU "CentaurHauls" - jne not_centaur - - movl $0x80000000, %eax # Use the CPUID instruction to check for cache info - cpuid - cmp $6, %al # Is cache info available? - jb id_done - - movl $0x80000005, %eax # Use the CPUID instruction to get L1 cache info - cpuid - movl %ecx, X86_CACHE(%esi) - movl %edx, X86_CACHE+4(%esi) - movl $0x80000006, %eax # Use the CPUID instruction to get L2 cache info - cpuid - movl %ecx, X86_CACHE+8(%esi) - - -not_centaur: -id_done: - movl %edi, %ebx /* Restore GOT pointer */ + call test_start - leal _dl_start@GOTOFF(%ebx), %eax - call *%eax - call do_test /* In case we return simulate an exception */ pushfl pushl %cs @@ -612,11 +363,12 @@ int_hand: pushl %esi pushl %ebp - /* original stack pointer */ - leal 20(%esp), %eax + /* original boot_stack pointer */ + leal 48(%esp), %eax pushl %eax - - pushl %esp /* pointer to structure on the stack */ + pushl %ds + pushl %ss + pushl %esp /* pointer to trap regs struct on the boot_stack */ call inter addl $8, %esp @@ -650,8 +402,8 @@ gdt_descr: gdt: .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* not used */ - .quad 0x00cf9a000000ffff /* 0x10 main 4gb code at 0x000000 */ - .quad 0x00cf92000000ffff /* 0x18 main 4gb data at 0x000000 */ + .quad 0x00cf9b000000ffff /* 0x10 main 4gb code at 0x000000 */ + .quad 0x00cf93000000ffff /* 0x18 main 4gb data at 0x000000 */ .word 0xFFFF # 16bit 64KB - (0x10000*1 = 64KB) .word 0 # base address = SETUPSEG @@ -690,6 +442,10 @@ maxdepth \depth-1 maxdepth +# Page Directory Tables: +# There are 4 tables, the first two map the first 2 GB of memory. The last two are used with # PAE to map +# the rest of memory in 2 GB segments. The last two tables are changed in vmem.c to map each segment. +# We use 2 MB pages so only the Page Directory Table is used (no page tables). .balign 4096 .globl pd0 pd0: @@ -710,6 +466,8 @@ pd2: pd3: ptes64 0x00000000C0000000 +# Legacy Mode Page Directory Pointer Table: +# 4 Entries, pointing to the Page Directory Tables .balign 4096 .globl pdp pdp: @@ -717,12 +475,31 @@ pdp: .long 0 .long pd1 + 1 .long 0 - .long pd2 + 1 .long 0 - .long pd3 + 1 .long 0 + +# Long Mode Page Directory Pointer Table: +# 4 Entries, pointing to the Page Directory Tables +.balign 4096 +lpdp: + .long pd0 + 3 + .long 0 + .long pd1 + 3 + .long 0 + .long pd2 + 3 + .long 0 + .long pd3 + 3 + .long 0 + + +# The long mode level 4 page map table +.balign 4096 +.globl pml4 +pml4: + .long lpdp + 3 + .long 0 .previous #define RSTART startup_32 @@ -788,8 +565,8 @@ query_pcbios: movl %eax, %fs movl %eax, %gs - /* Compute the stack base */ - leal stack@GOTOFF(%ebx), %ecx + /* Compute the boot_stack base */ + leal boot_stack@GOTOFF(%ebx), %ecx /* Compute the address of meminfo */ leal mem_info@GOTOFF(%ebx), %edi @@ -818,7 +595,7 @@ real: movw %ax, %gs movw %ax, %ss - /* Adjust the stack pointer */ + /* Adjust the boot_stack pointer */ movl %ecx, %eax shrl $4, %eax movw %ax, %ss @@ -991,8 +768,8 @@ prot: movl %eax, %gs movl %eax, %ss - /* Adjust the stack pointer */ - leal stack@GOTOFF(%ebx), %eax + /* Adjust the boot_stack pointer */ + leal boot_stack@GOTOFF(%ebx), %eax addl %eax, %esp /* Restore the caller saved registers */ @@ -1014,9 +791,45 @@ idt_real: .word 0x400 - 1 # idt limit ( 256 entries) .word 0, 0 # idt base = 0L +/* _ap_trampoline_start is the entry point for cpus other than the + * bootstrap cpu. The code between _ap_trampoline_start to + * _ap_trampoline_protmode is copied to BootCodeStart(0x9000). + * The ljmp after turning on CR0.PE will jump to the + * relocatable code which usually resides at 0x10000 + _ap_trampoline_protmode. + * + * The trampoline code uses a temporary GDT. The entries of this temporary + * GDT must match the first few entries of the GDT used by the relocatble + * memtest code(see 'gdt' sybmol in this file). + * + */ + .globl _ap_trampoline_start + .globl _ap_trampoline_protmode + .code16 +_ap_trampoline_start: + lgdt 0x0 /* will be fixed up later, see smp.c:BootAP()*/ + movl %cr0, %eax + orl $1, %eax + movl %eax, %cr0 + data32 ljmp $KERNEL_CS, $_ap_trampoline_protmode +_ap_trampoline_protmode: + .code32 + movw $KERNEL_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + movl $(LOW_TEST_ADR + _GLOBAL_OFFSET_TABLE_), %esp + leal boot_stack_top@GOTOFF(%esp), %esp + pushl $0 + popf + call startup_32 + /* if we ever return, we'll just loop forever */ + cli +2: hlt + jmp 2b .data zerobss: .long 1 -clear_display: .long 1 .previous .data .balign 16 @@ -1026,7 +839,9 @@ mem_info: .previous .bss .balign 16 -stack: - . = . + 8192 -stack_top: +boot_stack: + .globl boot_stack + . = . + 4096 +boot_stack_top: + .globl boot_stack_top .previous @@ -1,59 +1,82 @@ -/* init.c - MemTest-86 Version 3.0 - * - * Released under version 2 of the Gnu Public License. - * By Chris Brady, cbrady@sgi.com - * ---------------------------------------------------- - * MemTest86+ V4.20 Specific code (GPL V2.0) +/* + * MemTest86+ V5 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.canardpc.com - http://www.memtest.org + * ------------------------------------------------ + * init.c - MemTest-86 Version 3.6 + * + * Released under version 2 of the Gnu Public License. + * By Chris Brady */ + +#include "stdin.h" +#include "stddef.h" #include "test.h" #include "defs.h" #include "config.h" -#include "controller.h" -#include "pci.h" +#include "cpuid.h" +#include "smp.h" #include "io.h" #include "spd.h" - -#define rdmsr(msr,val1,val2) \ - __asm__ __volatile__("rdmsr" \ - : "=a" (val1), "=d" (val2) \ - : "c" (msr)) +#include "pci.h" +#include "controller.h" extern struct tseq tseq[]; extern short memsz_mode; -extern short firmware; -extern short dmi_initialized; -extern int dmi_err_cnts[MAX_DMI_MEMDEVS]; - -struct cpu_ident cpu_id; -ulong st_low, st_high; -ulong end_low, end_high; -ulong cal_low, cal_high; -ulong extclock; +extern int num_cpus; +extern int act_cpus; +extern int found_cpus; unsigned long imc_type = 0; +extern int maxcpus; +extern char cpu_mask[]; +extern void initialise_cpus(); + +/* Here we store all of the cpuid data */ +extern struct cpu_ident cpu_id; -int l1_cache, l2_cache, l3_cache; +int l1_cache=0, l2_cache=0, l3_cache=0; int tsc_invariable = 0; +ulong extclock; -ulong memspeed(ulong src, ulong len, int iter, int type); +ulong memspeed(ulong src, ulong len, int iter); static void cpu_type(void); -static void cacheable(void); static int cpuspeed(void); -int beepmode, fail_safe; +static void get_cache_size(); +static void cpu_cache_speed(); +void get_cpuid(); +int beepmode; +extern short dmi_initialized; +extern int dmi_err_cnts[MAX_DMI_MEMDEVS]; /* Failsafe function */ /* msec: number of ms to wait - scs: scancode expected to stop */ +/* bits: 0 = extended detection - 1: SMP - 2: Temp Check */ +/* 3: MP SMP - 4-7: RSVD */ void failsafe(int msec, int scs) { - int ip; + int i; ulong sh, sl, l, h, t; unsigned char c; + volatile char *pp; - cprint(18, 22, "Press *F1* to enter Fail-Safe Mode"); + for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(18*2)+1); i<40; i++, pp+=2) { + *pp = 0x1E; + } + for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(18*2)+1); i<3; i++, pp+=2) { + *pp = 0x9E; + } + for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(55*2)+1); i<3; i++, pp+=2) { + *pp = 0x9E; + } - ip = 0; + cprint(18, 18, "==> Press F1 to enter Fail-Safe Mode <=="); + + if(v->fail_safe & 2) + { + cprint(19, 15, "==> Press F2 to force Multi-Threading (SMP) <=="); + } + /* save the starting time */ asm __volatile__( "rdtsc":"=a" (sl),"=d" (sh)); @@ -73,34 +96,63 @@ void failsafe(int msec, int scs) t += (l / v->clks_msec); /* Is the time up? */ - if (t >= msec) { - cprint(18, 22, " "); - break; - } + if (t >= msec) { break; } /* Is expected Scan code pressed? */ c = get_key(); c &= 0x7f; - if(c == scs) { - fail_safe = 1; - cprint(18, 22, " "); + /* F1 */ + if(c == scs) { v->fail_safe |= 1; break; } + + /* F2 */ + if(c == scs+1) + { + v->fail_safe ^= 2; break; - } + + } + + /* F3 */ + if(c == scs+2) + { + if(v->fail_safe & 2) { v->fail_safe ^= 2; } + v->fail_safe |= 8; + break; + } + } + + cprint(18, 18, " "); + cprint(19, 15, " "); + + for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(18*2)+1); i<40; i++, pp+=2) { + *pp = 0x17; + } + } + + static void display_init(void) { int i; volatile char *pp; + + /* Set HW cursor out of screen boundaries */ + __outb(0x0F, 0x03D4); + __outb(0xFF, 0x03D5); + + __outb(0x0E, 0x03D4); + __outb(0xFF, 0x03D5); + serial_echo_init(); - serial_echo_print("\x1B[LINE_SCROLL;24r"); /* Set scroll area row 7-23 */ - serial_echo_print("\x1B[H\x1B[2J"); /* Clear Screen */ - serial_echo_print("\x1B[37m\x1B[44m"); - serial_echo_print("\x1B[0m"); - serial_echo_print("\x1B[37m\x1B[44m"); + serial_echo_print("[LINE_SCROLL;24r"); /* Set scroll area row 7-23 */ + serial_echo_print("[H[2J"); /* Clear Screen */ + serial_echo_print("[37m[44m"); + serial_echo_print("[0m"); + serial_echo_print("[37m[44m"); /* Clear screen & set background to blue */ for(i=0, pp=(char *)(SCREEN_ADR); i<80*24; i++) { @@ -108,12 +160,13 @@ static void display_init(void) *pp++ = 0x17; } - /* Make the name background red */ + /* Make the name background green */ for(i=0, pp=(char *)(SCREEN_ADR+1); i<TITLE_WIDTH; i++, pp+=2) { *pp = 0x20; } - cprint(0, 0, " Memtest86 v4.20 "); + cprint(0, 0, " Memtest86 5.01 "); + /* Set Blinking "+" */ for(i=0, pp=(char *)(SCREEN_ADR+1); i<2; i++, pp+=30) { *pp = 0xA4; } @@ -124,7 +177,7 @@ static void display_init(void) *pp = 0x71; } - serial_echo_print("\x1B[0m"); + serial_echo_print("[0m"); } /* @@ -142,31 +195,49 @@ void init(void) /* Setup the display */ display_init(); - - /* Determine the memory map */ - if ((firmware == FIRMWARE_UNKNOWN) && - (memsz_mode != SZ_MODE_PROBE)) { - if (query_linuxbios()) { - firmware = FIRMWARE_LINUXBIOS; - } - else if (query_pcbios()) { - firmware = FIRMWARE_PCBIOS; - } + cprint(5, 60, "| Time: 0:00:00"); + cprint(1, COL_MID,"Pass %"); + cprint(2, COL_MID,"Test %"); + cprint(3, COL_MID,"Test #"); + cprint(4, COL_MID,"Testing: "); + cprint(5, COL_MID,"Pattern: "); + cprint(1, 0, "CLK: (32b Mode)"); + cprint(2, 0, "L1 Cache: Unknown "); + cprint(3, 0, "L2 Cache: Unknown "); + cprint(4, 0, "L3 Cache: None "); + cprint(5, 0, "Memory : "); + cprint(6, 0, "------------------------------------------------------------------------------"); + cprint(7, 0, "Core#:"); + cprint(8, 0, "State:"); + cprint(9, 0, "Cores: Active / Total (Run: All) | Pass: 0 Errors: 0 "); + cprint(10, 0, "------------------------------------------------------------------------------"); + + /* + for(i=0, pp=(char *)(SCREEN_ADR+(5*160)+(53*2)+1); i<20; i++, pp+=2) { + *pp = 0x92; } - mem_size(); + for(i=0, pp=(char *)(SCREEN_ADR+0*160+1); i<80; i++, pp+=2) { + *pp = 0x47; + } + */ + + cprint(7, 39, "| Chipset : Unknown"); + cprint(8, 39, "| Memory Type : Unknown"); + - /* setup pci */ - pci_init(); + for(i=0; i < 6; i++) { + cprint(i, COL_MID-2, "| "); + } + + footer(); - /* setup beep mode */ - beepmode = BEEP_MODE; + aprint(5, 10, v->test_pages); - v->test = 0; - v->pass = 0; - v->msg_line = 0; - v->ecount = 0; - v->ecc_ecount = 0; + v->pass = 0; + v->msg_line = 0; + v->ecount = 0; + v->ecc_ecount = 0; v->testsel = -1; v->msg_line = LINE_SCROLL-1; v->scroll_start = v->msg_line * 160; @@ -183,7 +254,7 @@ void init(void) v->erri.ebits = 0; v->erri.hdr_flag = 0; v->erri.tbits = 0; - for (i=0; tseq[i].msg != 0; i++) { + for (i=0; tseq[i].msg != NULL; i++) { tseq[i].errors = 0; } if (dmi_initialized) { @@ -193,984 +264,727 @@ void init(void) } } } + + /* setup beep mode */ + beepmode = BEEP_MODE; + + /* Get the cpu and cache information */ + get_cpuid(); + + /* setup pci */ + pci_init(); - cprint(LINE_CPU+1, 0, "L1 Cache: Unknown "); - cprint(LINE_CPU+2, 0, "L2 Cache: Unknown "); - cprint(LINE_CPU+3, 0, "L3 Cache: None "); - cprint(LINE_CPU+4, 0, "Memory : |-------------------------------------------------"); - aprint(LINE_CPU+4, 10, v->test_pages); - cprint(LINE_CPU+5, 0, "Chipset : "); + get_cache_size(); cpu_type(); - /* Check fail safe */ - failsafe(2000, 0x3B); + cpu_cache_speed(); - /* Find the memory controller */ - find_controller(); + /* Check fail safe */ + failsafe(5000, 0x3B); - /* Find Memory Specs */ - if(fail_safe == 0) { get_spd_spec(); } + /* Initalize SMP */ + initialise_cpus(); + + for (i = 0; i <num_cpus; i++) { + dprint(7, i+7, i%10, 1, 0); + cprint(8, i+7, "S"); + } - if (v->rdtsc) { - cacheable(); - cprint(LINE_TIME, COL_TIME+4, ": :"); + dprint(9, 19, num_cpus, 2, 0); + + if((v->fail_safe & 3) == 2) + { + cprint(LINE_CPU,9, "(SMP: Disabled)"); + cprint(LINE_RAM,9, "Running..."); } - cprint(0, COL_MID,"Pass %"); - cprint(1, COL_MID,"Test %"); - cprint(2, COL_MID,"Test #"); - cprint(3, COL_MID,"Testing: "); - cprint(4, COL_MID,"Pattern: "); - cprint(LINE_INFO-2, 0, " WallTime Cached RsvdMem MemMap Cache ECC Test Pass Errors ECC Errs"); - cprint(LINE_INFO-1, 0, " --------- ------ ------- -------- ----- --- ---- ---- ------ --------"); - cprint(LINE_INFO, COL_TST, " Std"); - cprint(LINE_INFO, COL_PASS, " 0"); - cprint(LINE_INFO, COL_ERR, " 0"); - cprint(LINE_INFO+1, 0, " -----------------------------------------------------------------------------"); - + // dprint(10, 5, found_cpus, 2, 0); - for(i=0; i < 5; i++) { - cprint(i, COL_MID-2, "| "); + /* Find Memory Specs */ + if(v->fail_safe & 1) + { + cprint(LINE_CPU, COL_SPEC, " **** FAIL SAFE **** FAIL SAFE **** "); + cprint(LINE_RAM, COL_SPEC, " No detection, same reliability "); + } else { + find_controller(); + get_spd_spec(); + if(num_cpus <= 16 && !(v->fail_safe & 4)) { coretemp(); } + } + + if(v->check_temp > 0 && !(v->fail_safe & 4)) + { + cprint(LINE_CPU, 26, "| CPU Temp"); + cprint(LINE_CPU+1, 26, "| øC"); } - footer(); - // Default Print Mode - // v->printmode=PRINTMODE_SUMMARY; + + beep(600); + beep(1000); + + /* Record the start time */ + asm __volatile__ ("rdtsc":"=a" (v->startl),"=d" (v->starth)); + v->snapl = v->startl; + v->snaph = v->starth; + if (l1_cache == 0) { l1_cache = 64; } + if (l2_cache == 0) { l1_cache = 512; } v->printmode=PRINTMODE_ADDRESSES; v->numpatn=0; - -} - -#define FLAT 0 - -static unsigned long mapped_window = 1; -void paging_off(void) -{ - if (!v->pae) - return; - mapped_window = 1; - __asm__ __volatile__ ( - /* Disable paging */ - "movl %%cr0, %%eax\n\t" - "andl $0x7FFFFFFF, %%eax\n\t" - "movl %%eax, %%cr0\n\t" - /* Disable pae and pse */ - "movl %%cr4, %%eax\n\t" - "and $0xCF, %%al\n\t" - "movl %%eax, %%cr4\n\t" - : - : - : "ax" - ); } -static void paging_on(void *pdp) +/* Get cache sizes for most AMD and Intel CPUs, exceptions for old CPUs are + * handled in CPU detection */ +void get_cache_size() { - if (!v->pae) - return; - __asm__ __volatile__( - /* Load the page table address */ - "movl %0, %%cr3\n\t" - /* Enable pae */ - "movl %%cr4, %%eax\n\t" - "orl $0x00000020, %%eax\n\t" - "movl %%eax, %%cr4\n\t" - /* Enable paging */ - "movl %%cr0, %%eax\n\t" - "orl $0x80000000, %%eax\n\t" - "movl %%eax, %%cr0\n\t" - : - : "r" (pdp) - : "ax" - ); -} - -int map_page(unsigned long page) -{ - unsigned long i; - struct pde { - unsigned long addr_lo; - unsigned long addr_hi; - }; - extern unsigned char pdp[]; - extern struct pde pd2[]; - unsigned long window = page >> 19; - if (FLAT || (window == mapped_window)) { - return 0; - } - if (window == 0) { - return 0; - } - if (!v->pae || (window >= 32)) { - /* Fail either we don't have pae support - * or we want an address that is out of bounds - * even for pae. - */ - return -1; - } - /* Compute the page table entries... */ - for(i = 0; i < 1024; i++) { - /*-----------------10/30/2004 12:37PM--------------- - * 0xE3 -- - * Bit 0 = Present bit. 1 = PDE is present - * Bit 1 = Read/Write. 1 = memory is writable - * Bit 2 = Supervisor/User. 0 = Supervisor only (CPL 0-2) - * Bit 3 = Writethrough. 0 = writeback cache policy - * Bit 4 = Cache Disable. 0 = page level cache enabled - * Bit 5 = Accessed. 1 = memory has been accessed. - * Bit 6 = Dirty. 1 = memory has been written to. - * Bit 7 = Page Size. 1 = page size is 2 MBytes - * --------------------------------------------------*/ - pd2[i].addr_lo = ((window & 1) << 31) + ((i & 0x3ff) << 21) + 0xE3; - pd2[i].addr_hi = (window >> 1); - } - paging_off(); - if (window > 1) { - paging_on(pdp); - } - mapped_window = window; - return 0; -} + int i, j, n, size; + unsigned int v[4]; + unsigned char *dp = (unsigned char *)v; + struct cpuid4_eax *eax = (struct cpuid4_eax *)&v[0]; + struct cpuid4_ebx *ebx = (struct cpuid4_ebx *)&v[1]; + struct cpuid4_ecx *ecx = (struct cpuid4_ecx *)&v[2]; + + switch(cpu_id.vend_id.char_array[0]) { + /* AMD Processors */ + case 'A': + //l1_cache = cpu_id.cache_info.amd.l1_i_sz; + l1_cache = cpu_id.cache_info.amd.l1_d_sz; + l2_cache = cpu_id.cache_info.amd.l2_sz; + l3_cache = cpu_id.cache_info.amd.l3_sz; + l3_cache *= 512; + break; + case 'G': + /* Intel Processors */ + l1_cache = 0; + l2_cache = 0; + l3_cache = 0; + + /* Use CPUID(4) if it is available */ + if (cpu_id.max_cpuid > 3) { + + /* figure out how many cache leaves */ + n = -1; + do + { + ++n; + /* Do cpuid(4) loop to find out num_cache_leaves */ + cpuid_count(4, n, &v[0], &v[1], &v[2], &v[3]); + } while ((eax->ctype) != 0); + + /* loop through all of the leaves */ + for (i=0; i<n; i++) + { + cpuid_count(4, i, &v[0], &v[1], &v[2], &v[3]); + + /* Check for a valid cache type */ + if (eax->ctype == 1 || eax->ctype == 3) + { + + /* Compute the cache size */ + size = (ecx->number_of_sets + 1) * + (ebx->coherency_line_size + 1) * + (ebx->physical_line_partition + 1) * + (ebx->ways_of_associativity + 1); + size /= 1024; + + switch (eax->level) + { + case 1: + l1_cache += size; + break; + case 2: + l2_cache += size; + break; + case 3: + l3_cache += size; + break; + } + } + } + return; + } -void *mapping(unsigned long page_addr) -{ - void *result; - if (FLAT || (page_addr < 0x80000)) { - /* If the address is less that 1GB directly use the address */ - result = (void *)(page_addr << 12); - } - else { - unsigned long alias; - alias = page_addr & 0x7FFFF; - alias += 0x80000; - result = (void *)(alias << 12); + /* No CPUID(4) so we use the older CPUID(2) method */ + /* Get number of times to iterate */ + cpuid(2, &v[0], &v[1], &v[2], &v[3]); + n = v[0] & 0xff; + for (i=0 ; i<n ; i++) { + cpuid(2, &v[0], &v[1], &v[2], &v[3]); + + /* If bit 31 is set, this is an unknown format */ + for (j=0 ; j<3 ; j++) { + if (v[j] & (1 << 31)) { + v[j] = 0; + } + } + + /* Byte 0 is level count, not a descriptor */ + for (j = 1 ; j < 16 ; j++) { + switch(dp[j]) { + case 0x6: + case 0xa: + case 0x66: + l1_cache += 8; + break; + case 0x8: + case 0xc: + case 0xd: + case 0x60: + case 0x67: + l1_cache += 16; + break; + case 0xe: + l1_cache += 24; + break; + case 0x9: + case 0x2c: + case 0x30: + case 0x68: + l1_cache += 32; + break; + case 0x39: + case 0x3b: + case 0x41: + case 0x79: + l2_cache += 128; + break; + case 0x3a: + l2_cache += 192; + break; + case 0x21: + case 0x3c: + case 0x3f: + case 0x42: + case 0x7a: + case 0x82: + l2_cache += 256; + break; + case 0x3d: + l2_cache += 384; + break; + case 0x3e: + case 0x43: + case 0x7b: + case 0x7f: + case 0x80: + case 0x83: + case 0x86: + l2_cache += 512; + break; + case 0x44: + case 0x78: + case 0x7c: + case 0x84: + case 0x87: + l2_cache += 1024; + break; + case 0x45: + case 0x7d: + case 0x85: + l2_cache += 2048; + break; + case 0x48: + l2_cache += 3072; + break; + case 0x4e: + l2_cache += 6144; + break; + case 0x23: + case 0xd0: + l3_cache += 512; + break; + case 0xd1: + case 0xd6: + l3_cache += 1024; + break; + case 0x25: + case 0xd2: + case 0xd7: + case 0xdc: + case 0xe2: + l3_cache += 2048; + break; + case 0x29: + case 0x46: + case 0x49: + case 0xd8: + case 0xdd: + case 0xe3: + l3_cache += 4096; + break; + case 0x4a: + l3_cache += 6144; + break; + case 0x47: + case 0x4b: + case 0xde: + case 0xe4: + l3_cache += 8192; + break; + case 0x4c: + case 0xea: + l3_cache += 12288; + break; + case 0x4d: + l3_cache += 16384; + break; + case 0xeb: + l3_cache += 18432; + break; + case 0xec: + l3_cache += 24576; + break; + } /* end switch */ + } /* end for 1-16 */ + } /* end for 0 - n */ } - return result; } -void *emapping(unsigned long page_addr) +/* + * Find IMC type and set global variables accordingly + */ +void detect_imc(void) { - void *result; - result = mapping(page_addr -1); - /* The result needs to be 256 byte alinged... */ - result = ((unsigned char *)result) + 0xf00; - return result; + // Check AMD IMC + if(cpu_id.vend_id.char_array[0] == 'A' && cpu_id.vers.bits.family == 0xF) + { + switch(cpu_id.vers.bits.extendedFamily) + { + case 0x0: + imc_type = 0x0100; // Old K8 + break; + case 0x1: + case 0x2: + imc_type = 0x0101; // K10 (Family 10h & 11h) + break; + case 0x3: + imc_type = 0x0102; // A-Series APU (Family 12h) + break; + case 0x5: + imc_type = 0x0103; // C- / E- / Z- Series APU (Family 14h) + break; + case 0x6: + imc_type = 0x0104; // FX Series (Family 15h) + break; + case 0x7: + imc_type = 0x0105; // Kabini & related (Family 16h) + break; + } + return; + } + + // Check Intel IMC + if(cpu_id.vend_id.char_array[0] == 'G' && cpu_id.vers.bits.family == 6 && cpu_id.vers.bits.extendedModel) + { + switch(cpu_id.vers.bits.model) + { + case 0x5: + if(cpu_id.vers.bits.extendedModel == 2) { imc_type = 0x0003; } // Core i3/i5 1st Gen 45 nm (NHM) + if(cpu_id.vers.bits.extendedModel == 3) { v->fail_safe |= 4; } // Atom Clover Trail + if(cpu_id.vers.bits.extendedModel == 4) { imc_type = 0x0007; } // HSW-ULT + break; + case 0x6: + if(cpu_id.vers.bits.extendedModel == 3) { + imc_type = 0x0009; // Atom Cedar Trail + v->fail_safe |= 4; // Disable Core temp + } + break; + case 0xA: + switch(cpu_id.vers.bits.extendedModel) + { + case 0x1: + imc_type = 0x0001; // Core i7 1st Gen 45 nm (NHME) + break; + case 0x2: + imc_type = 0x0004; // Core 2nd Gen (SNB) + break; + case 0x3: + imc_type = 0x0006; // Core 3nd Gen (IVB) + break; + } + break; + case 0xC: + switch(cpu_id.vers.bits.extendedModel) + { + case 0x1: + if(cpu_id.vers.bits.stepping > 9) { imc_type = 0x0008; } // Atom PineView + v->fail_safe |= 4; // Disable Core temp + break; + case 0x2: + imc_type = 0x0002; // Core i7 1st Gen 32 nm (WMR) + break; + case 0x3: + imc_type = 0x0007; // Core 4nd Gen (HSW) + break; + } + break; + case 0xD: + imc_type = 0x0005; // SNB-E + break; + case 0xE: + imc_type = 0x0001; // Core i7 1st Gen 45 nm (NHM) + break; + } + + if(imc_type) { tsc_invariable = 1; } + return; + } } -unsigned long page_of(void *addr) +void smp_default_mode(void) { - unsigned long page; - page = ((unsigned long)addr) >> 12; - if (!FLAT && (page >= 0x80000)) { - page &= 0x7FFFF; - page += mapped_window << 19; - } -#if 0 - cprint(LINE_SCROLL -2, 0, "page_of( )-> "); - hprint(LINE_SCROLL -2, 8, ((unsigned long)addr)); - hprint(LINE_SCROLL -2, 20, page); -#endif - return page; + int i, result; + char *cpupsn = cpu_id.brand_id.char_array; + char *disabledcpu[] = { "Opteron", "Xeon", "Genuine Intel" }; + + for(i = 0; i < 3; i++) + { + result = strstr(cpupsn , disabledcpu[i]); + if(result != -1) { v->fail_safe |= 0b10; } + } + + // For 5.01 release, SMP disabled by defualt by config.h toggle + if(CONSERVATIVE_SMP) { v->fail_safe |= 0b10; } + } - /* - * Find CPU type and cache sizes + * Find CPU type */ - - void cpu_type(void) { - int i, off=0; - int l1_cache=0, l2_cache=0, l3_cache=0; - ulong speed; - - v->rdtsc = 0; - v->pae = 0; - -#ifdef CPUID_DEBUG - dprint(9,0,cpu_id.type,3,1); - dprint(10,0,cpu_id.model,3,1); - dprint(11,0,cpu_id.cpuid,3,1); -#endif - - /* If the CPUID instruction is not supported then this is */ - /* a 386, 486 or one of the early Cyrix CPU's */ - if (cpu_id.cpuid < 1) { - switch (cpu_id.type) { - case 2: - /* This is a Cyrix CPU without CPUID */ - i = getCx86(0xfe); - i &= 0xf0; - i >>= 4; - switch(i) { - case 0: - case 1: - cprint(LINE_CPU, 0, "Cyrix Cx486"); - break; - case 2: - cprint(LINE_CPU, 0,"Cyrix 5x86"); - break; - case 3: - cprint(LINE_CPU, 0,"Cyrix 6x86"); - break; - case 4: - cprint(LINE_CPU, 0,"Cyrix MediaGX"); - break; - case 5: - cprint(LINE_CPU, 0,"Cyrix 6x86MX"); - break; - case 6: - cprint(LINE_CPU, 0,"Cyrix MII"); - break; - default: - cprint(LINE_CPU, 0,"Cyrix ???"); - break; - } - break; - case 3: - cprint(LINE_CPU, 0, "386"); - break; - - case 4: - cprint(LINE_CPU, 0, "486"); - l1_cache = 8; - break; - } + /* If we can get a brand string use it, and we are done */ + if (cpu_id.max_xcpuid >= 0x80000004) { + cprint(0, COL_MID, cpu_id.brand_id.char_array); + //If we have a brand string, maybe we have an IMC. Check that. + detect_imc(); + smp_default_mode(); return; } - /* We have cpuid so we can see if we have pae support */ - if (cpu_id.capability & (1 << X86_FEATURE_PAE)) { - v->pae = 1; - } - switch(cpu_id.vend_id[0]) { + /* The brand string is not available so we need to figure out + * CPU what we have */ + switch(cpu_id.vend_id.char_array[0]) { /* AMD Processors */ case 'A': - switch(cpu_id.type) { + switch(cpu_id.vers.bits.family) { case 4: - switch(cpu_id.model) { + switch(cpu_id.vers.bits.model) { case 3: - cprint(LINE_CPU, 0, "AMD 486DX2"); + cprint(0, COL_MID, "AMD 486DX2"); break; case 7: - cprint(LINE_CPU, 0, "AMD 486DX2-WB"); + cprint(0, COL_MID, "AMD 486DX2-WB"); break; case 8: - cprint(LINE_CPU, 0, "AMD 486DX4"); + cprint(0, COL_MID, "AMD 486DX4"); break; case 9: - cprint(LINE_CPU, 0, "AMD 486DX4-WB"); + cprint(0, COL_MID, "AMD 486DX4-WB"); break; case 14: - cprint(LINE_CPU, 0, "AMD 5x86-WT"); + cprint(0, COL_MID, "AMD 5x86-WT"); + break; + case 15: + cprint(0, COL_MID, "AMD 5x86-WB"); break; } /* Since we can't get CPU speed or cache info return */ return; case 5: - switch(cpu_id.model) { + switch(cpu_id.vers.bits.model) { case 0: case 1: case 2: case 3: - cprint(LINE_CPU, 0, "AMD K5"); + cprint(0, COL_MID, "AMD K5"); l1_cache = 8; - off = 6; break; case 6: case 7: - cprint(LINE_CPU, 0, "AMD K6"); - off = 6; - l1_cache = cpu_id.cache_info[3]; - l1_cache += cpu_id.cache_info[7]; + cprint(0, COL_MID, "AMD K6"); break; case 8: - cprint(LINE_CPU, 0, "AMD K6-2"); - off = 8; - l1_cache = cpu_id.cache_info[3]; - l1_cache += cpu_id.cache_info[7]; + cprint(0, COL_MID, "AMD K6-2"); break; case 9: - cprint(LINE_CPU, 0, "AMD K6-III"); - off = 10; - l1_cache = cpu_id.cache_info[3]; - l1_cache += cpu_id.cache_info[7]; - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; + cprint(0, COL_MID, "AMD K6-III"); break; - case 10: - cprint(LINE_CPU, 0, "AMD Geode LX"); - off = 12; - l1_cache = cpu_id.cache_info[3]; - l1_cache += cpu_id.cache_info[7]; - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; - break; - case 13: - cprint(LINE_CPU, 0, "AMD K6-III+"); - off = 11; - l1_cache = cpu_id.cache_info[3]; - l1_cache += cpu_id.cache_info[7]; - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; + case 13: + cprint(0, COL_MID, "AMD K6-III+"); break; } break; case 6: - switch(cpu_id.model) { + + switch(cpu_id.vers.bits.model) { case 1: - cprint(LINE_CPU, 0, "AMD Athlon (0.25)"); - off = 17; - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; + cprint(0, COL_MID, "AMD Athlon (0.25)"); break; case 2: case 4: - cprint(LINE_CPU, 0, "AMD Athlon (0.18)"); - off = 17; - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; + cprint(0, COL_MID, "AMD Athlon (0.18)"); break; case 6: - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; if (l2_cache == 64) { - cprint(LINE_CPU, 0, "AMD Duron (0.18)"); + cprint(0, COL_MID, "AMD Duron (0.18)"); } else { - cprint(LINE_CPU, 0, "Athlon XP (0.18)"); + cprint(0, COL_MID, "Athlon XP (0.18)"); } - off = 16; break; case 8: case 10: - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; if (l2_cache == 64) { - cprint(LINE_CPU, 0, "AMD Duron (0.13)"); + cprint(0, COL_MID, "AMD Duron (0.13)"); } else { - cprint(LINE_CPU, 0, "Athlon XP (0.13)"); + cprint(0, COL_MID, "Athlon XP (0.13)"); } - off = 16; break; case 3: case 7: - cprint(LINE_CPU, 0, "AMD Duron"); - off = 9; + cprint(0, COL_MID, "AMD Duron"); /* Duron stepping 0 CPUID for L2 is broken */ /* (AMD errata T13)*/ - if (cpu_id.step == 0) { /* stepping 0 */ - /* Hard code the right size*/ + if (cpu_id.vers.bits.stepping == 0) { /* stepping 0 */ + /* Hard code the right L2 size */ l2_cache = 64; } else { - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; } break; } - l1_cache = cpu_id.cache_info[3]; - l1_cache += cpu_id.cache_info[7]; break; - case 15: - l1_cache = cpu_id.cache_info[3]; - l2_cache = (cpu_id.cache_info[11] << 8); - l2_cache += cpu_id.cache_info[10]; - imc_type = 0x0100; - if(((cpu_id.ext >> 16) & 0xFF) < 0x10) { - // Here if CPUID.EXT < 0x10h (old K8/K10) - switch(cpu_id.model) { - default: - cprint(LINE_CPU, 0, "AMD K8"); - off = 6; - break; - case 1: - case 5: - if (((cpu_id.ext >> 16) & 0xF) != 0) { - cprint(LINE_CPU, 0, "AMD Opteron (0.09)"); - } else { - cprint(LINE_CPU, 0, "AMD Opteron (0.13)"); - } - off = 18; - break; - case 3: - case 11: - cprint(LINE_CPU, 0, "Athlon 64 X2"); - off = 12; - break; - case 8: - cprint(LINE_CPU, 0, "Turion 64 X2"); - off = 12; - break; - case 4: - case 7: - case 12: - case 14: - case 15: - if (((cpu_id.ext >> 16) & 0xF) != 0) { - if (l2_cache > 256) { - cprint(LINE_CPU, 0, "Athlon 64 (0.09)"); - } else { - cprint(LINE_CPU, 0, "Sempron (0.09)"); - } - } else { - if (l2_cache > 256) { - cprint(LINE_CPU, 0, "Athlon 64 (0.13)"); - } else { - cprint(LINE_CPU, 0, "Sempron (0.13)"); - } - } - off = 16; - break; - } - break; - } else { - // Here if CPUID.EXT >= 0x10h (new K10) - l3_cache = (cpu_id.cache_info[15] << 8); - l3_cache += (cpu_id.cache_info[14] >> 2); - l3_cache *= 512; - switch(cpu_id.model) { - case 1: - imc_type = 0x0102; - cprint(LINE_CPU, 0, "AMD Fusion @"); - off = 12; - break; - default: - case 2: - imc_type = 0x0101; - cprint(LINE_CPU, 0, "AMD K10 (65nm) @"); - off = 16; - break; - case 4: - imc_type = 0x0101; - cprint(LINE_CPU, 0, "AMD K10 (45nm) @"); - off = 16; - break; - case 9: - imc_type = 0x0101; - cprint(LINE_CPU, 0, "AMD Magny-Cours"); - off = 15; - break; - } - break; - } + + /* All AMD family values >= 10 have the Brand ID + * feature so we don't need to find the CPU type */ } break; /* Intel or Transmeta Processors */ case 'G': - if ( cpu_id.vend_id[7] == 'T' ) { /* GenuineTMx86 */ - if (cpu_id.type == 5) { - cprint(LINE_CPU, 0, "TM 5x00"); - off = 7; - } else if (cpu_id.type == 15) { - cprint(LINE_CPU, 0, "TM 8x00"); - off = 7; + if ( cpu_id.vend_id.char_array[7] == 'T' ) { /* GenuineTMx86 */ + if (cpu_id.vers.bits.family == 5) { + cprint(0, COL_MID, "TM 5x00"); + } else if (cpu_id.vers.bits.family == 15) { + cprint(0, COL_MID, "TM 8x00"); } - l1_cache = cpu_id.cache_info[3] + cpu_id.cache_info[7]; - l2_cache = (cpu_id.cache_info[11]*256) + cpu_id.cache_info[10]; + l1_cache = cpu_id.cache_info.ch[3] + cpu_id.cache_info.ch[7]; + l2_cache = (cpu_id.cache_info.ch[11]*256) + cpu_id.cache_info.ch[10]; } else { /* GenuineIntel */ - if (cpu_id.type == 4) { - switch(cpu_id.model) { - case 0: - case 1: - cprint(LINE_CPU, 0, "Intel 486DX"); - off = 11; - break; - case 2: - cprint(LINE_CPU, 0, "Intel 486SX"); - off = 11; - break; - case 3: - cprint(LINE_CPU, 0, "Intel 486DX2"); - off = 12; - break; - case 4: - cprint(LINE_CPU, 0, "Intel 486SL"); - off = 11; - break; - case 5: - cprint(LINE_CPU, 0, "Intel 486SX2"); - off = 12; - break; - case 7: - cprint(LINE_CPU, 0, "Intel 486DX2-WB"); - off = 15; - break; - case 8: - cprint(LINE_CPU, 0, "Intel 486DX4"); - off = 12; - break; - case 9: - cprint(LINE_CPU, 0, "Intel 486DX4-WB"); - off = 15; - break; - } - /* Since we can't get CPU speed or cache info return */ - return; + if (cpu_id.vers.bits.family == 4) { + switch(cpu_id.vers.bits.model) { + case 0: + case 1: + cprint(0, COL_MID, "Intel 486DX"); + break; + case 2: + cprint(0, COL_MID, "Intel 486SX"); + break; + case 3: + cprint(0, COL_MID, "Intel 486DX2"); + break; + case 4: + cprint(0, COL_MID, "Intel 486SL"); + break; + case 5: + cprint(0, COL_MID, "Intel 486SX2"); + break; + case 7: + cprint(0, COL_MID, "Intel 486DX2-WB"); + break; + case 8: + cprint(0, COL_MID, "Intel 486DX4"); + break; + case 9: + cprint(0, COL_MID, "Intel 486DX4-WB"); + break; } + /* Since we can't get CPU speed or cache info return */ + return; + } - /* Get the cache info */ - for (i=0; i<16; i++) { -#ifdef CPUID_DEBUG - dprint(12,i*3,cpu_id.cache_info[i],2,1); -#endif - switch(cpu_id.cache_info[i]) { - case 0x6: - case 0xa: - case 0x66: + + switch(cpu_id.vers.bits.family) { + case 5: + switch(cpu_id.vers.bits.model) { + case 0: + case 1: + case 2: + case 3: + case 7: + cprint(0, COL_MID, "Pentium"); + if (l1_cache == 0) { l1_cache = 8; - break; - case 0x8: - case 0xc: - case 0x67: - case 0x60: + } + break; + case 4: + case 8: + cprint(0, COL_MID, "Pentium-MMX"); + if (l1_cache == 0) { l1_cache = 16; - break; - case 0x9: - case 0xd: - case 0x68: - case 0x2c: - case 0x30: - l1_cache = 32; - break; - case 0x40: - l2_cache = 0; - break; - case 0x41: - case 0x79: - case 0x39: - case 0x3b: - l2_cache = 128; - break; - case 0x3a: - l2_cache = 192; - break; - case 0x21: - case 0x42: - case 0x7a: - case 0x82: - case 0x3c: - case 0x3f: - l2_cache = 256; - break; - case 0x3d: - l2_cache = 384; - break; - case 0x43: - case 0x7b: - case 0x83: - case 0x86: - case 0x3e: - case 0x7f: - case 0x80: - l2_cache = 512; - break; - case 0x44: - case 0x7c: - case 0x84: - case 0x87: - case 0x78: - l2_cache = 1024; - break; - case 0x45: - case 0x7d: - case 0x85: - l2_cache = 2048; - break; - case 0x48: - l2_cache = 3072; - break; - case 0x49: - l2_cache = 4096; - break; - case 0x4e: - l2_cache = 6144; - break; - case 0x22: - case 0xd0: - l3_cache = 512; - case 0x23: - case 0xd1: - case 0xd6: - l3_cache = 1024; - break; - case 0xdc: - l3_cache = 1536; - break; - case 0x25: - case 0xd2: - case 0xd7: - case 0xe2: - l3_cache = 2048; - break; - case 0xdd: - l3_cache = 3072; - break; - case 0x29: - case 0x46: - case 0xd8: - case 0xe3: - l3_cache = 4096; - break; - case 0x4a: - case 0xde: - l3_cache = 6144; - break; - case 0x47: - case 0x4b: - case 0xe4: - l3_cache = 8192; - break; - case 0x4c: - case 0xea: - l3_cache = 12288; - break; - case 0x4d: - l3_cache = 16374; - break; - case 0xeb: - l3_cache = 18432; - break; - case 0xec: - l3_cache = 24576; - break; } + break; } - - // If no cache found, check if deterministic cache info are available - if(l1_cache == 0 && ((cpu_id.dcache0_eax >> 5) & 7) == 1) - { - - long dcache[] = { cpu_id.dcache0_eax, cpu_id.dcache0_ebx, cpu_id.dcache0_ecx, cpu_id.dcache0_edx, - cpu_id.dcache1_eax, cpu_id.dcache1_ebx, cpu_id.dcache1_ecx, cpu_id.dcache1_edx, - cpu_id.dcache2_eax, cpu_id.dcache2_ebx, cpu_id.dcache2_ecx, cpu_id.dcache2_edx, - cpu_id.dcache3_eax, cpu_id.dcache3_ebx, cpu_id.dcache3_ecx, cpu_id.dcache3_edx - }; - - for(i=0; i<4; i++) - { - switch((dcache[i*4] >> 5) & 7) - { - case 1: - // We don't want L1 I-Cache, only L1 D-Cache - if((dcache[i*4] & 3) != 2) - { - l1_cache = (((dcache[i*4+1] >> 22) & 0x3FF) + 1) * (((dcache[i*4+1] >> 12) & 0x3FF) + 1); - l1_cache *= ((dcache[i*4+1] & 0xFFF) + 1) * (dcache[i*4+2] + 1) / 1024; - } - break; - case 2: - l2_cache = (((dcache[i*4+1] >> 22) & 0x3FF) + 1) * (((dcache[i*4+1] >> 12) & 0x3FF) + 1); - l2_cache *= ((dcache[i*4+1] & 0xFFF) + 1) * (dcache[i*4+2] + 1) / 1024; - break; - case 3: - l3_cache = (((dcache[i*4+1] >> 22) & 0x3FF) + 1) * (((dcache[i*4+1] >> 12) & 0x3FF) + 1); - l3_cache *= ((dcache[i*4+1] & 0xFFF) + 1) * (dcache[i*4+2] + 1) / 1024; - break; - } - } - } - - - switch(cpu_id.type) { + break; + case 6: + switch(cpu_id.vers.bits.model) { + case 0: + case 1: + cprint(0, COL_MID, "Pentium Pro"); + break; + case 3: + case 4: + cprint(0, COL_MID, "Pentium II"); + break; case 5: - switch(cpu_id.model) { - case 0: - case 1: - case 2: - case 3: - case 7: - cprint(LINE_CPU, 0, "Pentium"); - if (l1_cache == 0) { - l1_cache = 8; - } - off = 7; - break; - case 4: - case 8: - cprint(LINE_CPU, 0, "Pentium-MMX"); - if (l1_cache == 0) { - l1_cache = 16; - } - off = 11; - break; + if (l2_cache == 0) { + cprint(0, COL_MID, "Celeron"); + } else { + cprint(0, COL_MID, "Pentium II"); } break; case 6: - switch(cpu_id.model) { - case 0: - case 1: - cprint(LINE_CPU, 0, "Pentium Pro"); - off = 11; - break; - case 3: - cprint(LINE_CPU, 0, "Pentium II"); - off = 10; - break; - case 5: - if ((cpu_id.ext >> 16) & 0xF) { - if(((cpu_id.ext >> 16) & 0xF) > 1) { - cprint(LINE_CPU, 0, "Intel Core i3/i5"); - tsc_invariable = 1; - imc_type = 0x0003; - off = 16; - } else { - cprint(LINE_CPU, 0, "Intel EP80579"); - if (l2_cache == 0) { l2_cache = 256; } - off = 13; - } + if (l2_cache == 128) { + cprint(0, COL_MID, "Celeron"); + } else { + cprint(0, COL_MID, "Pentium II"); + } + } + break; + case 7: + case 8: + case 11: + if (l2_cache == 128) { + cprint(0, COL_MID, "Celeron"); } else { - if (l2_cache == 0) { - cprint(LINE_CPU, 0, "Celeron"); - off = 7; - } else { - cprint(LINE_CPU, 0, "Pentium II"); - off = 10; - } - } - break; - case 6: - if (l2_cache == 128) { - cprint(LINE_CPU, 0, "Celeron"); - off = 7; - } else { - cprint(LINE_CPU, 0, "Pentium II"); - off = 10; - } - break; - case 7: - case 8: - case 11: - if (((cpu_id.ext >> 16) & 0xF) != 0) { - tsc_invariable = 1; - if (l2_cache < 1024) { - cprint(LINE_CPU, 0, "Celeron"); - off = 7; - } else { - cprint(LINE_CPU, 0, "Intel Core 2"); - off = 12; - } - } else { - if (l2_cache == 128) { - cprint(LINE_CPU, 0, "Celeron"); - off = 7; - } else { - cprint(LINE_CPU, 0, "Pentium III"); - off = 11; - } - } - break; - case 9: - if (l2_cache == 512) { - cprint(LINE_CPU, 0, "Celeron M (0.13)"); - } else { - cprint(LINE_CPU, 0, "Pentium M (0.13)"); - } - off = 16; - break; - case 10: - if (((cpu_id.ext >> 16) & 0xF) != 0) { - tsc_invariable = 1; - if(((cpu_id.ext >> 16) & 0xF) > 1) { - cprint(LINE_CPU, 0, "Intel Core Gen2"); - imc_type = 0x0004; - off = 15; - } else { - imc_type = 0x0001; - cprint(LINE_CPU, 0, "Intel Core i7"); - off = 13; - } - } else { - cprint(LINE_CPU, 0, "Pentium III Xeon"); - off = 16; - } - break; - case 12: - if (((cpu_id.ext >> 16) & 0xF) > 1) { - cprint(LINE_CPU, 0, "Core i7 (32nm)"); - tsc_invariable = 1; - imc_type = 0x0002; - off = 14; - } else { - l1_cache = 24; - cprint(LINE_CPU, 0, "Atom (0.045)"); - off = 12; - } - break; - case 13: - if (l2_cache == 1024) { - cprint(LINE_CPU, 0, "Celeron M (0.09)"); - } else { - cprint(LINE_CPU, 0, "Pentium M (0.09)"); - } - off = 16; - break; - case 14: - if (((cpu_id.ext >> 16) & 0xF) != 0) { - tsc_invariable = 1; - imc_type = 0x0001; - cprint(LINE_CPU, 0, "Intel Core i5/i7"); - off = 16; - } else { - cprint(LINE_CPU, 0, "Intel Core"); - off = 10; - } - break; - case 15: - if (l2_cache == 1024) { - cprint(LINE_CPU, 0, "Pentium E"); - off = 9; - } else { - cprint(LINE_CPU, 0, "Intel Core 2"); - off = 12; - } - tsc_invariable = 1; - break; + cprint(0, COL_MID, "Pentium III"); + } + break; + case 9: + if (l2_cache == 512) { + cprint(0, COL_MID, "Celeron M (0.13)"); + } else { + cprint(0, COL_MID, "Pentium M (0.13)"); + } + break; + case 10: + cprint(0, COL_MID, "Pentium III Xeon"); + break; + case 12: + l1_cache = 24; + cprint(0, COL_MID, "Atom (0.045)"); + break; + case 13: + if (l2_cache == 1024) { + cprint(0, COL_MID, "Celeron M (0.09)"); + } else { + cprint(0, COL_MID, "Pentium M (0.09)"); } break; + case 14: + cprint(0, COL_MID, "Intel Core"); + break; case 15: - switch(cpu_id.model) { - case 0: - case 1: - if (l2_cache == 128) { - cprint(LINE_CPU, 0, "Celeron (0.18)"); - off = 14; - } else if (cpu_id.pwrcap == 0x0B) { - cprint(LINE_CPU, 0, "Xeon DP (0.18)"); - off = 14; - } else if (cpu_id.pwrcap == 0x0C) { - cprint(LINE_CPU, 0, "Xeon MP (0.18)"); - off = 14; - } else { - cprint(LINE_CPU, 0, "Pentium 4 (0.18)"); - off = 16; - } - break; - case 2: - if (l2_cache == 128) { - cprint(LINE_CPU, 0, "Celeron (0.13)"); - off = 14; - } else if (cpu_id.pwrcap == 0x0B) { - cprint(LINE_CPU, 0, "Xeon DP (0.13)"); - off = 14; - } else if (cpu_id.pwrcap == 0x0C) { - cprint(LINE_CPU, 0, "Xeon MP (0.13)"); - off = 14; - } else { - cprint(LINE_CPU, 0, "Pentium 4 (0.13)"); - off = 16; - } - break; - case 3: - case 4: - if (l2_cache == 256) { - cprint(LINE_CPU, 0, "Celeron (0.09)"); - off = 14; - } else if (cpu_id.pwrcap == 0x0B) { - cprint(LINE_CPU, 0, "Xeon DP (0.09)"); - off = 14; - } else if (cpu_id.pwrcap == 0x0C) { - cprint(LINE_CPU, 0, "Xeon MP (0.09)"); - off = 14; - } else if ((cpu_id.step == 0x4 || cpu_id.step == 0x7) && cpu_id.model == 0x4) { - cprint(LINE_CPU, 0, "Pentium D (0.09)"); - off = 16; - } else { - cprint(LINE_CPU, 0, "Pentium 4 (0.09)"); - off = 16; - } - break; - case 6: - cprint(LINE_CPU, 0, "Pentium D (65nm)"); - off = 16; - break; - default: - cprint(LINE_CPU, 0, "Unknown Intel"); - off = 13; - break; + if (l2_cache == 1024) { + cprint(0, COL_MID, "Pentium E"); + } else { + cprint(0, COL_MID, "Intel Core 2"); } break; } + break; + case 15: + switch(cpu_id.vers.bits.model) { + case 0: + case 1: + case 2: + if (l2_cache == 128) { + cprint(0, COL_MID, "Celeron"); + } else { + cprint(0, COL_MID, "Pentium 4"); + } + break; + case 3: + case 4: + if (l2_cache == 256) { + cprint(0, COL_MID, "Celeron (0.09)"); + } else { + cprint(0, COL_MID, "Pentium 4 (0.09)"); + } + break; + case 6: + cprint(0, COL_MID, "Pentium D (65nm)"); + break; + default: + cprint(0, COL_MID, "Unknown Intel"); + break; + break; + } + } break; /* VIA/Cyrix/Centaur Processors with CPUID */ case 'C': - if ( cpu_id.vend_id[1] == 'e' ) { /* CentaurHauls */ - l1_cache = cpu_id.cache_info[3] + cpu_id.cache_info[7]; - l2_cache = cpu_id.cache_info[11]; - switch(cpu_id.type){ + if ( cpu_id.vend_id.char_array[1] == 'e' ) { /* CentaurHauls */ + l1_cache = cpu_id.cache_info.ch[3] + cpu_id.cache_info.ch[7]; + l2_cache = cpu_id.cache_info.ch[11]; + switch(cpu_id.vers.bits.family){ case 5: - cprint(LINE_CPU, 0, "Centaur 5x86"); - off = 12; + cprint(0, COL_MID, "Centaur 5x86"); break; case 6: // VIA C3 - switch(cpu_id.model){ - default: - if (cpu_id.step < 8) { - cprint(LINE_CPU, 0, "VIA C3 Samuel2"); - off = 14; - } else { - cprint(LINE_CPU, 0, "VIA C3 Eden"); - off = 11; - } - break; - case 10: - cprint(LINE_CPU, 0, "VIA C7 (C5J)"); - l1_cache = 64; - l2_cache = 128; - off = 16; - break; - case 13: - cprint(LINE_CPU, 0, "VIA C7 (C5R)"); - l1_cache = 64; - l2_cache = 128; - off = 12; - break; - case 15: - cprint(LINE_CPU, 0, "VIA Isaiah (CN)"); - l1_cache = 64; - l2_cache = 1024; - off = 15; - break; + switch(cpu_id.vers.bits.model){ + default: + if (cpu_id.vers.bits.stepping < 8) { + cprint(0, COL_MID, "VIA C3 Samuel2"); + } else { + cprint(0, COL_MID, "VIA C3 Eden"); + } + break; + case 10: + cprint(0, COL_MID, "VIA C7 (C5J)"); + l1_cache = 64; + l2_cache = 128; + break; + case 13: + cprint(0, COL_MID, "VIA C7 (C5R)"); + l1_cache = 64; + l2_cache = 128; + break; + case 15: + cprint(0, COL_MID, "VIA Isaiah (CN)"); + l1_cache = 64; + l2_cache = 128; + break; } } } else { /* CyrixInstead */ - switch(cpu_id.type) { + switch(cpu_id.vers.bits.family) { case 5: - switch(cpu_id.model) { + switch(cpu_id.vers.bits.model) { case 0: - cprint(LINE_CPU, 0, "Cyrix 6x86MX/MII"); - off = 16; + cprint(0, COL_MID, "Cyrix 6x86MX/MII"); break; case 4: - cprint(LINE_CPU, 0, "Cyrix GXm"); - off = 9; + cprint(0, COL_MID, "Cyrix GXm"); break; } return; case 6: // VIA C3 - switch(cpu_id.model) { + switch(cpu_id.vers.bits.model) { case 6: - cprint(LINE_CPU, 0, "Cyrix III"); - off = 9; + cprint(0, COL_MID, "Cyrix III"); break; case 7: - if (cpu_id.step < 8) { - cprint(LINE_CPU, 0, "VIA C3 Samuel2"); - off = 14; + if (cpu_id.vers.bits.stepping < 8) { + cprint(0, COL_MID, "VIA C3 Samuel2"); } else { - cprint(LINE_CPU, 0, "VIA C3 Ezra-T"); - off = 13; + cprint(0, COL_MID, "VIA C3 Ezra-T"); } break; case 8: - cprint(LINE_CPU, 0, "VIA C3 Ezra-T"); - off = 13; + cprint(0, COL_MID, "VIA C3 Ezra-T"); break; case 9: - cprint(LINE_CPU, 0, "VIA C3 Nehemiah"); - off = 15; + cprint(0, COL_MID, "VIA C3 Nehemiah"); break; } // L1 = L2 = 64 KB from Cyrix III to Nehemiah @@ -1180,34 +994,40 @@ void cpu_type(void) } } break; - /* Unknown processor */ default: - off = 3; /* Make a guess at the family */ - switch(cpu_id.type) { + switch(cpu_id.vers.bits.family) { case 5: - cprint(LINE_CPU, 0, "586"); - return; + cprint(0, COL_MID, "586"); case 6: - cprint(LINE_CPU, 0, "686"); - return; + cprint(0, COL_MID, "686"); + default: + cprint(0, COL_MID, "Unidentified Processor"); } } +} + +#define STEST_ADDR 0x100000 /* Measure memory speed starting at 1MB */ + +/* Measure and display CPU and cache sizes and speeds */ +void cpu_cache_speed() +{ + int i, off = 4; + ulong speed; - /* We are here only if the CPU type supports the rdtsc instruction */ /* Print CPU speed */ if ((speed = cpuspeed()) > 0) { - if (speed < 1000000-50) { + if (speed < 999499) { speed += 50; /* for rounding */ - cprint(LINE_CPU, off, " . MHz"); - dprint(LINE_CPU, off+1, speed/1000, 3, 1); - dprint(LINE_CPU, off+5, (speed/100)%10, 1, 0); + cprint(1, off, " . MHz"); + dprint(1, off+1, speed/1000, 3, 1); + dprint(1, off+5, (speed/100)%10, 1, 0); } else { speed += 500; /* for rounding */ - cprint(LINE_CPU, off, " MHz"); - dprint(LINE_CPU, off, speed/1000, 5, 0); + cprint(1, off, " MHz"); + dprint(1, off, speed/1000, 5, 0); } extclock = speed; } @@ -1216,11 +1036,11 @@ void cpu_type(void) /* To measure L1 cache speed we use a block size that is 1/4th */ /* of the total L1 cache size since half of it is for instructions */ if (l1_cache) { - cprint(LINE_CPU+1, 0, "L1 Cache: K "); - dprint(LINE_CPU+1, 11, l1_cache, 3, 0); - if ((speed=memspeed((ulong)mapping(0x100), (l1_cache / 4) * 1024, 200, MS_COPY))) { - cprint(LINE_CPU+1, 16, " MB/s"); - dprint(LINE_CPU+1, 16, speed, 6, 0); + cprint(2, 0, "L1 Cache: K "); + dprint(2, 11, l1_cache, 3, 0); + if ((speed=memspeed(STEST_ADDR, (l1_cache/2)*1024, 200))) { + cprint(2, 16, " MB/s"); + dprint(2, 16, speed, 6, 0); } } @@ -1229,119 +1049,84 @@ void cpu_type(void) /* the size of the L1 cache. We have to fudge if the L1 */ /* cache is bigger than the L2 */ if (l2_cache) { - cprint(LINE_CPU+2, 0, "L2 Cache: K "); - dprint(LINE_CPU+2, 10, l2_cache, 4, 0); - dprint(LINE_CPU+2, 10, l2_cache, 4, 0); + cprint(3, 0, "L2 Cache: K "); + dprint(3, 10, l2_cache, 4, 0); if (l2_cache < l1_cache) { i = l1_cache / 4 + l2_cache / 4; } else { i = l1_cache; } - if ((speed=memspeed((ulong)mapping(0x100), i*1024, 200, MS_COPY))) { - cprint(LINE_CPU+2, 16, " MB/s"); - dprint(LINE_CPU+2, 16, speed, 6, 0); + if ((speed=memspeed(STEST_ADDR, i*1024, 200))) { + cprint(3, 16, " MB/s"); + dprint(3, 16, speed, 6, 0); } } - /* Print out L3 cache info */ /* We measure the L3 cache speed by using a block size that is */ - /* the size of the L2 cache. */ - - if (l3_cache) { - cprint(LINE_CPU+3, 0, "L3 Cache: K "); - dprint(LINE_CPU+3, 10, l3_cache, 4, 0); - dprint(LINE_CPU+3, 10, l3_cache, 4, 0); - - i = l2_cache*2; + /* 2X the size of the L2 cache. */ + + if (l3_cache) + { + cprint(4, 0, "L3 Cache: K "); + aprint(4, 10, l3_cache/4); + //dprint(4, 10, l3_cache, 4, 0); + + i = l2_cache*2; + + if ((speed=memspeed(STEST_ADDR, i*1024, 150))) { + cprint(4, 16, " MB/s"); + dprint(4, 16, speed, 6, 0); + } + } +} - if ((speed=memspeed((ulong)mapping(0x100), i*1024, 150, MS_COPY))) { - cprint(LINE_CPU+3, 16, " MB/s"); - dprint(LINE_CPU+3, 16, speed, 6, 0); - } - } +/* Measure and display memory speed, multitasked using all CPUs */ +ulong spd[MAX_CPUS]; +void get_mem_speed(int me, int ncpus) +{ + int i; + ulong speed=0; + /* Determine memory speed. To find the memory speed we use + * A block size that is the sum of all the L1, L2 & L3 caches + * in all cpus * 6 */ + i = (l3_cache + l2_cache + l1_cache) * 4; - /* Determine memory speed. To find the memory speed we use */ - /* A block size that is 5x the sum of the L1, L2 & L3 caches */ - i = (l3_cache + l2_cache + l1_cache) * 5; - /* Make sure that we have enough memory to do the test */ + /* If not use all we have */ if ((1 + (i * 2)) > (v->plim_upper << 2)) { i = ((v->plim_upper <<2) - 1) / 2; } - if((speed = memspeed((ulong)mapping(0x100), i*1024, 50, MS_COPY))) { - cprint(LINE_CPU+4, 16, " MB/s"); - dprint(LINE_CPU+4, 16, speed, 6, 0); - } - - /* Record the starting time */ - asm __volatile__ ("rdtsc":"=a" (v->startl),"=d" (v->starth)); - v->snapl = v->startl; - v->snaph = v->starth; - v->rdtsc = 1; - if (l1_cache == 0) { l1_cache = 66; } - if (l2_cache == 0) { l1_cache = 666; } -} - -/* Find cache-able memory size */ -static void cacheable(void) -{ - ulong speed, pspeed; - ulong paddr, mem_top, cached; - - mem_top = v->pmap[v->msegs - 1].end; - cached = v->test_pages; - pspeed = 0; - for (paddr=0x200; paddr <= mem_top - 64; paddr+=0x400) { - int i; - int found; - /* See if the paddr is at a testable location */ - found = 0; - for(i = 0; i < v->msegs; i++) { - if ((v->pmap[i].start >= paddr) && - (v->pmap[i].end <= (paddr + 32))) { - found = 1; - break; - } - } - if (!found) { - continue; - } - /* Map the range and perform the test */ - map_page(paddr); - speed = memspeed((ulong)mapping(paddr), 32*4096, 1, MS_READ); - if (pspeed) { - if (speed < pspeed) { - cached -= 32; - } - pspeed = (ulong)((float)speed * 0.7); - } - } - aprint(LINE_INFO, COL_CACHE_TOP, cached); - /* Ensure the default set of pages are mapped */ - map_page(0); - map_page(0x80000); + + speed = memspeed(STEST_ADDR, i * 1024, 100); + cprint(5, 16, " MB/s"); + dprint(5, 16, speed, 6, 0); + } - /* #define TICKS 5 * 11832 (count = 6376)*/ /* #define TICKS (65536 - 12752) */ -/* #define TICKS (65536 - 8271) */ -#define TICKS 59659 /* Program counter to 50 ms = 59659 clks */ +#define TICKS 59659 /* 50 ms */ /* Returns CPU clock in khz */ +ulong stlow, sthigh; static int cpuspeed(void) { int loops; + ulong end_low, end_high; + + if (cpu_id.fid.bits.rdtsc == 0 ) { + return(-1); + } /* Setup timer */ outb((inb(0x61) & ~0x02) | 0x01, 0x61); - outb(0xb0, 0x43); + outb(0xb0, 0x43); outb(TICKS & 0xff, 0x42); outb(TICKS >> 8, 0x42); - asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high)); + asm __volatile__ ("rdtsc":"=a" (stlow),"=d" (sthigh)); loops = 0; do { @@ -1350,8 +1135,8 @@ static int cpuspeed(void) asm __volatile__ ( "rdtsc\n\t" \ - "subl st_low,%%eax\n\t" \ - "sbbl st_high,%%edx\n\t" \ + "subl stlow,%%eax\n\t" \ + "sbbl sthigh,%%edx\n\t" \ :"=a" (end_low), "=d" (end_high) ); @@ -1359,20 +1144,27 @@ static int cpuspeed(void) if (loops < 4 || end_low < 50000) { return(-1); } + v->clks_msec = end_low/50; - if(tsc_invariable){ end_low = correct_tsc(end_low); } + if (tsc_invariable) end_low = correct_tsc(end_low); - v->clks_msec = end_low/50; return(v->clks_msec); } -/* Measure cache/memory speed by copying a block of memory. */ +/* Measure cache speed by copying a block of memory. */ /* Returned value is kbytes/second */ -ulong memspeed(ulong src, ulong len, int iter, int type) +ulong memspeed(ulong src, ulong len, int iter) { - ulong dst; - ulong wlen; int i; + ulong dst, wlen; + ulong st_low, st_high; + ulong end_low, end_high; + ulong cal_low, cal_high; + + if (cpu_id.fid.bits.rdtsc == 0 ) { + return(-1); + } + if (len == 0) return(-2); dst = src + len; wlen = len / 4; /* Length is bytes */ @@ -1382,12 +1174,12 @@ ulong memspeed(ulong src, ulong len, int iter, int type) for (i=0; i<iter; i++) { asm __volatile__ ( "movl %0,%%esi\n\t" \ - "movl %1,%%edi\n\t" \ - "movl %2,%%ecx\n\t" \ - "cld\n\t" \ - "rep\n\t" \ - "movsl\n\t" \ - :: "g" (src), "g" (dst), "g" (0) + "movl %1,%%edi\n\t" \ + "movl %2,%%ecx\n\t" \ + "cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ + :: "g" (src), "g" (dst), "g" (0) : "esi", "edi", "ecx" ); } @@ -1404,76 +1196,31 @@ ulong memspeed(ulong src, ulong len, int iter, int type) /* Now measure the speed */ - switch (type) { - case MS_COPY: - /* Do the first copy to prime the cache */ - asm __volatile__ ( + /* Do the first copy to prime the cache */ + asm __volatile__ ( + "movl %0,%%esi\n\t" \ + "movl %1,%%edi\n\t" \ + "movl %2,%%ecx\n\t" \ + "cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ + :: "g" (src), "g" (dst), "g" (wlen) + : "esi", "edi", "ecx" + ); + asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high)); + for (i=0; i<iter; i++) { + asm __volatile__ ( "movl %0,%%esi\n\t" \ "movl %1,%%edi\n\t" \ - "movl %2,%%ecx\n\t" \ - "cld\n\t" \ - "rep\n\t" \ - "movsl\n\t" \ + "movl %2,%%ecx\n\t" \ + "cld\n\t" \ + "rep\n\t" \ + "movsl\n\t" \ :: "g" (src), "g" (dst), "g" (wlen) : "esi", "edi", "ecx" ); - asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high)); - for (i=0; i<iter; i++) { - asm __volatile__ ( - "movl %0,%%esi\n\t" \ - "movl %1,%%edi\n\t" \ - "movl %2,%%ecx\n\t" \ - "cld\n\t" \ - "rep\n\t" \ - "movsl\n\t" \ - :: "g" (src), "g" (dst), "g" (wlen) - : "esi", "edi", "ecx" - ); - } - asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high)); - break; - case MS_WRITE: - asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high)); - for (i=0; i<iter; i++) { - asm __volatile__ ( - "movl %0,%%ecx\n\t" \ - "movl %1,%%edi\n\t" \ - "movl %2,%%eax\n\t" \ - "rep\n\t" \ - "stosl\n\t" - :: "g" (wlen), "g" (dst), "g" (0) - : "edi", "ecx", "eax" - ); - } - asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high)); - break; - case MS_READ: - asm __volatile__ ( - "movl %0,%%esi\n\t" \ - "movl %1,%%ecx\n\t" \ - "cld\n\t" \ - "L1:\n\t" \ - "lodsl\n\t" \ - "loop L1\n\t" \ - :: "g" (src), "g" (wlen) - : "esi", "ecx" - ); - asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high)); - for (i=0; i<iter; i++) { - asm __volatile__ ( - "movl %0,%%esi\n\t" \ - "movl %1,%%ecx\n\t" \ - "cld\n\t" \ - "L2:\n\t" \ - "lodsl\n\t" \ - "loop L2\n\t" \ - :: "g" (src), "g" (wlen) - : "esi", "ecx", "eax" - ); - } - asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high)); - break; } + asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high)); /* Compute the elapsed time */ asm __volatile__ ( @@ -1493,32 +1240,35 @@ ulong memspeed(ulong src, ulong len, int iter, int type) ); /* Make sure that the result fits in 32 bits */ + //hprint(11,40,end_high); if (end_high) { - return(0); - } - - /* If this was a copy adjust the time */ - if (type == MS_COPY) { - end_low /= 2; + return(-3); } + end_low /= 2; /* Convert to clocks/KB */ end_low /= len; end_low *= 1024; end_low /= iter; if (end_low == 0) { - return(0); + return(-4); } - if(tsc_invariable){ end_low = correct_tsc(end_low); } - /* Convert to kbytes/sec */ + + if (tsc_invariable) end_low = correct_tsc(end_low); + return((v->clks_msec)/end_low); } +#define rdmsr(msr,val1,val2) \ + __asm__ __volatile__("rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) + + ulong correct_tsc(ulong el_org) { - float coef_now, coef_max; int msr_lo, msr_hi, is_xe; @@ -1535,7 +1285,7 @@ ulong correct_tsc(ulong el_org) if ((msr_lo >> 14) & 0x1) { coef_max = coef_max + 0.5f; } } - if((cpu_id.feature_flag >> 7) & 1) { + if(cpu_id.fid.bits.eist) { rdmsr(0x198, msr_lo, msr_hi); coef_now = ((msr_lo >> 8) & 0x1F); if ((msr_lo >> 14) & 0x1) { coef_now = coef_now + 0.5f; } @@ -1543,10 +1293,9 @@ ulong correct_tsc(ulong el_org) rdmsr(0x2A, msr_lo, msr_hi); coef_now = (msr_lo >> 22) & 0x1F; } - - if(coef_max && coef_now) { el_org = (ulong)(el_org * coef_now / coef_max); } - + if(coef_max && coef_now) { + el_org = (ulong)(el_org * coef_now / coef_max); + } return el_org; - } @@ -84,7 +84,6 @@ __OUTS(l) * - can't use it inside a inline function (it will never be true) * - you don't have to worry about side effects within the __builtin.. */ - #define outb(val,port) \ ((__builtin_constant_p((port)) && (port) < 256) ? \ __outbc((val),(port)) : \ @@ -1,6 +1,9 @@ -/* MemTest86+ V4.00 Specific code (GPL V2.0)
+/* MemTest86+ V5 Specific code (GPL V2.0)
* By Samuel DEMEULEMEESTER, sdemeule@memtest.org
* http://www.canardpc.com - http://www.memtest.org
+ * ------------------------------------------------
+ * Based on JEDEC JEP106-AG - January 2012
+ * All mo
*/
struct spd_jedec_manufacturer {
@@ -9,879 +12,975 @@ struct spd_jedec_manufacturer { char *name;
};
-struct spd_jedec_manufacturer jep106[] = {
- { 0, 0x01, "AMD"},
- { 0, 0x02, "AMI"},
- { 0, 0x83, "Fairchild"},
- { 0, 0x04, "Fujitsu"},
- { 0, 0x85, "GTE"},
- { 0, 0x86, "Harris"},
- { 0, 0x07, "Hitachi"},
- { 0, 0x08, "Inmos"},
- { 0, 0x89, "Intel"},
- { 0, 0x8a, "I.T.T."},
- { 0, 0x0b, "Intersil"},
- { 0, 0x8c, "Monolithic Memories"},
- { 0, 0x0d, "Mostek"},
- { 0, 0x0e, "Freescale (Motorola)"},
- { 0, 0x8f, "National"},
- { 0, 0x10, "NEC"},
- { 0, 0x91, "RCA"},
- { 0, 0x92, "Raytheon"},
- { 0, 0x13, "Conexant (Rockwell)"},
- { 0, 0x94, "Seeq"},
- { 0, 0x15, "NXP (Philips)"},
- { 0, 0x16, "Synertek"},
- { 0, 0x97, "Texas Instruments"},
- { 0, 0x98, "Toshiba"},
- { 0, 0x19, "Xicor"},
- { 0, 0x1a, "Zilog"},
- { 0, 0x9b, "Eurotechnique"},
- { 0, 0x1c, "Mitsubishi"},
- { 0, 0x9d, "Lucent (AT&T)"},
- { 0, 0x9e, "Exel"},
- { 0, 0x1f, "Atmel"},
- { 0, 0x20, "SGS/Thomson"},
- { 0, 0xa1, "Lattice Semi."},
- { 0, 0xa2, "NCR"},
- { 0, 0x23, "Wafer Scale Integration"},
- { 0, 0xa4, "IBM"},
- { 0, 0x25, "Tristar"},
- { 0, 0x26, "Visic"},
- { 0, 0xa7, "Intl. CMOS Technology"},
- { 0, 0xa8, "SSSI"},
- { 0, 0x29, "MicrochipTechnology"},
- { 0, 0x2a, "Ricoh"},
- { 0, 0xab, "VLSI"},
- { 0, 0x2c, "Micron Technology"},
- { 0, 0xad, "Hynix Semiconductor"},
- { 0, 0xae, "OKI Semiconductor"},
- { 0, 0x2f, "ACTEL"},
- { 0, 0xb0, "Sharp"},
- { 0, 0x31, "Catalyst"},
- { 0, 0x32, "Panasonic"},
- { 0, 0xb3, "IDT"},
- { 0, 0x34, "Cypress"},
- { 0, 0xb5, "DEC"},
- { 0, 0xb6, "LSI Logic"},
- { 0, 0x37, "Zarlink (Plessey)"},
- { 0, 0x38, "UTMC"},
- { 0, 0xb9, "Thinking Machine"},
- { 0, 0xba, "Thomson CSF"},
- { 0, 0x3b, "Integrated CMOS (Vertex)"},
- { 0, 0xbc, "Honeywell"},
- { 0, 0x3d, "Tektronix"},
- { 0, 0x3e, "Sun Microsystems"},
- { 0, 0xbf, "SST"},
- { 0, 0x40, "ProMos/Mosel Vitelic"},
- { 0, 0xc1, "Infineon (Siemens)"},
- { 0, 0xc2, "Macronix"},
- { 0, 0x43, "Xerox"},
- { 0, 0xc4, "Plus Logic"},
- { 0, 0x45, "SanDisk"},
- { 0, 0x46, "Elan Circuit Tech."},
- { 0, 0xc7, "European Silicon Str."},
- { 0, 0xc8, "Apple Computer"},
- { 0, 0x49, "Xilinx"},
- { 0, 0x4a, "Compaq"},
- { 0, 0xcb, "Protocol Engines"},
- { 0, 0x4c, "SCI"},
- { 0, 0xcd, "Seiko Instruments"},
- { 0, 0xce, "Samsung"},
- { 0, 0x4f, "I3 Design System"},
- { 0, 0xd0, "Klic"},
- { 0, 0x51, "Crosspoint Solutions"},
- { 0, 0x52, "Alliance Semiconductor"},
- { 0, 0xd3, "Tandem"},
- { 0, 0x54, "Hewlett-Packard"},
- { 0, 0xd5, "Intg. Silicon Solutions"},
- { 0, 0xd6, "Brooktree"},
- { 0, 0x57, "New Media"},
- { 0, 0x58, "MHS Electronic"},
- { 0, 0xd9, "Performance Semi."},
- { 0, 0xda, "Winbond Electronic"},
- { 0, 0x5b, "Kawasaki Steel"},
- { 0, 0xdc, "Bright Micro"},
- { 0, 0x5d, "TECMAR"},
- { 0, 0x5e, "Exar"},
- { 0, 0xdf, "PCMCIA"},
- { 0, 0xe0, "LG Semi (Goldstar)"},
- { 0, 0x61, "Northern Telecom"},
- { 0, 0x62, "Sanyo"},
- { 0, 0xe3, "Array Microsystems"},
- { 0, 0x64, "Crystal Semiconductor"},
- { 0, 0xe5, "Analog Devices"},
- { 0, 0xe6, "PMC-Sierra"},
- { 0, 0x67, "Asparix"},
- { 0, 0x68, "Convex Computer"},
- { 0, 0xe9, "Quality Semiconductor"},
- { 0, 0xea, "Nimbus Technology"},
- { 0, 0x6b, "Transwitch"},
- { 0, 0xec, "Micronas (ITT Intermetall)"},
- { 0, 0x6d, "Cannon"},
- { 0, 0x6e, "Altera"},
- { 0, 0xef, "NEXCOM"},
- { 0, 0x70, "QUALCOMM"},
- { 0, 0xf1, "Sony"},
- { 0, 0xf2, "Cray Research"},
- { 0, 0x73, "AMS(Austria Micro)"},
- { 0, 0xf4, "Vitesse"},
- { 0, 0x75, "Aster Electronics"},
- { 0, 0x76, "Bay Networks (Synoptic)"},
- { 0, 0xf7, "Zentrum/ZMD"},
- { 0, 0xf8, "TRW"},
- { 0, 0x79, "Thesys"},
- { 0, 0x7a, "Solbourne Computer"},
- { 0, 0xfb, "Allied-Signal"},
- { 0, 0x7c, "Dialog"},
- { 0, 0xfd, "Media Vision"},
- { 0, 0xfe, "Numonyx"},
- { 1, 0x01, "Cirrus Logic"},
- { 1, 0x02, "National Instruments"},
- { 1, 0x83, "ILC Data Device"},
- { 1, 0x04, "Alcatel Mietec"},
- { 1, 0x85, "Micro Linear"},
- { 1, 0x86, "Univ. of NC"},
- { 1, 0x07, "JTAG Technologies"},
- { 1, 0x08, "BAE Systems (Loral)"},
- { 1, 0x89, "Nchip"},
- { 1, 0x8a, "Galileo Tech"},
- { 1, 0x0b, "Bestlink Systems"},
- { 1, 0x8c, "Graychip"},
- { 1, 0x0d, "GENNUM"},
- { 1, 0x0e, "VideoLogic"},
- { 1, 0x8f, "Robert Bosch"},
- { 1, 0x10, "Chip Express"},
- { 1, 0x91, "DATARAM"},
- { 1, 0x92, "United Microelectronics Corp."},
- { 1, 0x13, "TCSI"},
- { 1, 0x94, "Smart Modular"},
- { 1, 0x15, "Hughes Aircraft"},
- { 1, 0x16, "Lanstar Semiconductor"},
- { 1, 0x97, "Qlogic"},
- { 1, 0x98, "Kingston"},
- { 1, 0x19, "Music Semi"},
- { 1, 0x1a, "Ericsson Components"},
- { 1, 0x9b, "SpaSE"},
- { 1, 0x1c, "Eon Silicon Devices"},
- { 1, 0x9d, "Programmable Micro Corp"},
- { 1, 0x9e, "DoD"},
- { 1, 0x1f, "Integ. Memories Tech."},
- { 1, 0x20, "Corollary"},
- { 1, 0xa1, "Dallas Semiconductor"},
- { 1, 0xa2, "Omnivision"},
- { 1, 0x23, "EIV(Switzerland)"},
- { 1, 0xa4, "Novatel Wireless"},
- { 1, 0x25, "Zarlink (Mitel)"},
- { 1, 0x26, "Clearpoint"},
- { 1, 0xa7, "Cabletron"},
- { 1, 0xa8, "STEC (Silicon Tech)"},
- { 1, 0x29, "Vanguard"},
- { 1, 0x2a, "Hagiwara Sys-Com"},
- { 1, 0xab, "Vantis"},
- { 1, 0x2c, "Celestica"},
- { 1, 0xad, "Century"},
- { 1, 0xae, "Hal Computers"},
- { 1, 0x2f, "Rohm Company"},
- { 1, 0xb0, "Juniper Networks"},
- { 1, 0x31, "Libit Signal Processing"},
- { 1, 0x32, "Mushkin Enhanced Memory"},
- { 1, 0xb3, "Tundra Semiconductor"},
- { 1, 0x34, "Adaptec"},
- { 1, 0xb5, "LightSpeed Semi."},
- { 1, 0xb6, "ZSP Corp."},
- { 1, 0x37, "AMIC Technology"},
- { 1, 0x38, "Adobe Systems"},
- { 1, 0xb9, "Dynachip"},
- { 1, 0xba, "PNY Electronics"},
- { 1, 0x3b, "Newport Digital"},
- { 1, 0xbc, "MMC Networks"},
- { 1, 0x3d, "T Square"},
- { 1, 0x3e, "Seiko Epson"},
- { 1, 0xbf, "Broadcom"},
- { 1, 0x40, "Viking Components"},
- { 1, 0xc1, "V3 Semiconductor"},
- { 1, 0xc2, "Flextronics (Orbit Semiconductor)"},
- { 1, 0x43, "Suwa Electronics"},
- { 1, 0xc4, "Transmeta"},
- { 1, 0x45, "Micron CMS"},
- { 1, 0x46, "American Computer & Digital Components"},
- { 1, 0xc7, "Enhance 3000"},
- { 1, 0xc8, "Tower Semiconductor"},
- { 1, 0x49, "CPU Design"},
- { 1, 0x4a, "Price Point"},
- { 1, 0xcb, "Maxim Integrated Product"},
- { 1, 0x4c, "Tellabs"},
- { 1, 0xcd, "Centaur Technology"},
- { 1, 0xce, "Unigen"},
- { 1, 0x4f, "Transcend Information"},
- { 1, 0xd0, "Memory Card Technology"},
- { 1, 0x51, "CKD"},
- { 1, 0x52, "Capital Instruments"},
- { 1, 0xd3, "Aica Kogyo"},
- { 1, 0x54, "Linvex Technology"},
- { 1, 0xd5, "MSC Vertriebs"},
- { 1, 0xd6, "AKM Company"},
- { 1, 0x57, "Dynamem"},
- { 1, 0x58, "NERA ASA"},
- { 1, 0xd9, "GSI Technology"},
- { 1, 0xda, "Dane-Elec (C Memory)"},
- { 1, 0x5b, "Acorn Computers"},
- { 1, 0xdc, "Lara Technology"},
- { 1, 0x5d, "Oak Technology"},
- { 1, 0x5e, "Itec Memory"},
- { 1, 0xdf, "Tanisys Technology"},
- { 1, 0xe0, "Truevision"},
- { 1, 0x61, "Wintec Industries"},
- { 1, 0x62, "Super PC Memory"},
- { 1, 0xe3, "MGV Memory"},
- { 1, 0x64, "Galvantech"},
- { 1, 0xe5, "Gadzoox Networks"},
- { 1, 0xe6, "Multi Dimensional Cons."},
- { 1, 0x67, "GateField"},
- { 1, 0x68, "Integrated Memory System"},
- { 1, 0xe9, "Triscend"},
- { 1, 0xea, "XaQti"},
- { 1, 0x6b, "Goldenram"},
- { 1, 0xec, "Clear Logic"},
- { 1, 0x6d, "Cimaron Communications"},
- { 1, 0x6e, "Nippon Steel Semi. Corp."},
- { 1, 0xef, "Advantage Memory"},
- { 1, 0x70, "AMCC"},
- { 1, 0xf1, "LeCroy"},
- { 1, 0xf2, "Yamaha"},
- { 1, 0x73, "Digital Microwave"},
- { 1, 0xf4, "NetLogic Microsystems"},
- { 1, 0x75, "MIMOS Semiconductor"},
- { 1, 0x76, "Advanced Fibre"},
- { 1, 0xf7, "BF Goodrich Data."},
- { 1, 0xf8, "Epigram"},
- { 1, 0x79, "Acbel Polytech"},
- { 1, 0x7a, "Apacer Technology"},
- { 1, 0xfb, "Admor Memory"},
- { 1, 0x7c, "FOXCONN"},
- { 1, 0xfd, "Quadratics Superconductor"},
- { 1, 0xfe, "3COM"},
- { 2, 0x01, "Camintonn"},
- { 2, 0x02, "ISOA"},
- { 2, 0x83, "Agate Semiconductor"},
- { 2, 0x04, "ADMtek"},
- { 2, 0x85, "HYPERTEC"},
- { 2, 0x86, "Adhoc Technologies"},
- { 2, 0x07, "MOSAID Technologies"},
- { 2, 0x08, "Ardent Technologies"},
- { 2, 0x89, "Switchcore"},
- { 2, 0x8a, "Cisco Systems"},
- { 2, 0x0b, "Allayer Technologies"},
- { 2, 0x8c, "WorkX AG (Wichman)"},
- { 2, 0x0d, "Oasis Semiconductor"},
- { 2, 0x0e, "Novanet Semiconductor"},
- { 2, 0x8f, "E-M Solutions"},
- { 2, 0x10, "Power General"},
- { 2, 0x91, "Advanced Hardware Arch."},
- { 2, 0x92, "Inova Semiconductors"},
- { 2, 0x13, "Telocity"},
- { 2, 0x94, "Delkin Devices"},
- { 2, 0x15, "Symagery Microsystems"},
- { 2, 0x16, "C-Port"},
- { 2, 0x97, "SiberCore Technologies"},
- { 2, 0x98, "Southland Microsystems"},
- { 2, 0x19, "Malleable Technologies"},
- { 2, 0x1a, "Kendin Communications"},
- { 2, 0x9b, "Great Technology Microcomputer"},
- { 2, 0x1c, "Sanmina"},
- { 2, 0x9d, "HADCO"},
- { 2, 0x9e, "Corsair"},
- { 2, 0x1f, "Actrans System"},
- { 2, 0x20, "ALPHA Technologies"},
- { 2, 0xa1, "Silicon Laboratories (Cygnal)"},
- { 2, 0xa2, "Artesyn Technologies"},
- { 2, 0x23, "Align Manufacturing"},
- { 2, 0xa4, "Peregrine Semiconductor"},
- { 2, 0x25, "Chameleon Systems"},
- { 2, 0x26, "Aplus Flash Technology"},
- { 2, 0xa7, "MIPS Technologies"},
- { 2, 0xa8, "Chrysalis ITS"},
- { 2, 0x29, "ADTEC"},
- { 2, 0x2a, "Kentron Technologies"},
- { 2, 0xab, "Win Technologies"},
- { 2, 0x2c, "Tachyon Semiconductor (ASIC)"},
- { 2, 0xad, "Extreme Packet Devices"},
- { 2, 0xae, "RF Micro Devices"},
- { 2, 0x2f, "Siemens AG"},
- { 2, 0xb0, "Sarnoff"},
- { 2, 0x31, "Itautec SA"},
- { 2, 0x32, "Radiata"},
- { 2, 0xb3, "Benchmark Elect. (AVEX)"},
- { 2, 0x34, "Legend"},
- { 2, 0xb5, "SpecTek"},
- { 2, 0xb6, "Hi/fn"},
- { 2, 0x37, "Enikia"},
- { 2, 0x38, "SwitchOn Networks"},
- { 2, 0xb9, "AANetcom"},
- { 2, 0xba, "Micro Memory Bank"},
- { 2, 0x3b, "ESS Technology"},
- { 2, 0xbc, "Virata"},
- { 2, 0x3d, "Excess Bandwidth"},
- { 2, 0x3e, "West Bay Semiconductor"},
- { 2, 0xbf, "DSP Group"},
- { 2, 0x40, "Newport Communications"},
- { 2, 0xc1, "Chip2Chip"},
- { 2, 0xc2, "Phobos"},
- { 2, 0x43, "Intellitech"},
- { 2, 0xc4, "Nordic VLSI ASA"},
- { 2, 0x45, "Ishoni Networks"},
- { 2, 0x46, "Silicon Spice"},
- { 2, 0xc7, "Alchemy Semiconductor"},
- { 2, 0xc8, "Agilent Technologies"},
- { 2, 0x49, "Centillium Communications"},
- { 2, 0x4a, "W.L. Gore"},
- { 2, 0xcb, "HanBit Electronics"},
- { 2, 0x4c, "GlobeSpan"},
- { 2, 0xcd, "Element 14"},
- { 2, 0xce, "Pycon"},
- { 2, 0x4f, "Saifun Semiconductors"},
- { 2, 0xd0, "Sibyte,"},
- { 2, 0x51, "MetaLink Technologies"},
- { 2, 0x52, "Feiya Technology"},
- { 2, 0xd3, "I & C Technology"},
- { 2, 0x54, "Shikatronics"},
- { 2, 0xd5, "Elektrobit"},
- { 2, 0xd6, "Megic"},
- { 2, 0x57, "Com-Tier"},
- { 2, 0x58, "Malaysia Micro Solutions"},
- { 2, 0xd9, "Hyperchip"},
- { 2, 0xda, "Gemstone Communications"},
- { 2, 0x5b, "Anadigm (Anadyne)"},
- { 2, 0xdc, "3ParData"},
- { 2, 0x5d, "Mellanox Technologies"},
- { 2, 0x5e, "Tenx Technologies"},
- { 2, 0xdf, "Helix AG"},
- { 2, 0xe0, "Domosys"},
- { 2, 0x61, "Skyup Technology"},
- { 2, 0x62, "HiNT"},
- { 2, 0xe3, "Chiaro"},
- { 2, 0x64, "MDT Technologies"},
- { 2, 0xe5, "Exbit Technology A/S"},
- { 2, 0xe6, "Integrated Technology Express"},
- { 2, 0x67, "AVED Memory"},
- { 2, 0x68, "Legerity"},
- { 2, 0xe9, "Jasmine Networks"},
- { 2, 0xea, "Caspian Networks"},
- { 2, 0x6b, "nCUBE"},
- { 2, 0xec, "Silicon Access Networks"},
- { 2, 0x6d, "FDK"},
- { 2, 0x6e, "High Bandwidth Access"},
- { 2, 0xef, "MultiLink Technology"},
- { 2, 0x70, "BRECIS"},
- { 2, 0xf1, "World Wide Packets"},
- { 2, 0xf2, "APW"},
- { 2, 0x73, "Chicory Systems"},
- { 2, 0xf4, "Xstream Logic"},
- { 2, 0x75, "Fast-Chip"},
- { 2, 0x76, "Zucotto Wireless"},
- { 2, 0xf7, "Realchip"},
- { 2, 0xf8, "Galaxy Power"},
- { 2, 0x79, "eSilicon"},
- { 2, 0x7a, "Morphics Technology"},
- { 2, 0xfb, "Accelerant Networks"},
- { 2, 0x7c, "Silicon Wave"},
- { 2, 0xfd, "SandCraft"},
- { 2, 0xfe, "Elpida"},
- { 3, 0x01, "Solectron"},
- { 3, 0x02, "Optosys Technologies"},
- { 3, 0x83, "Buffalo (Formerly Melco)"},
- { 3, 0x04, "TriMedia Technologies"},
- { 3, 0x85, "Cyan Technologies"},
- { 3, 0x86, "Global Locate"},
- { 3, 0x07, "Optillion"},
- { 3, 0x08, "Terago Communications"},
- { 3, 0x89, "Ikanos Communications"},
- { 3, 0x8a, "Preton Technology"},
- { 3, 0x0b, "Nanya Technology"},
- { 3, 0x8c, "Elite Flash Storage"},
- { 3, 0x0d, "Mysticom"},
- { 3, 0x0e, "LightSand Communications"},
- { 3, 0x8f, "ATI Technologies"},
- { 3, 0x10, "Agere Systems"},
- { 3, 0x91, "NeoMagic"},
- { 3, 0x92, "AuroraNetics"},
- { 3, 0x13, "Golden Empire"},
- { 3, 0x94, "Mushkin"},
- { 3, 0x15, "Tioga Technologies"},
- { 3, 0x16, "Netlist"},
- { 3, 0x97, "TeraLogic"},
- { 3, 0x98, "Cicada Semiconductor"},
- { 3, 0x19, "Centon Electronics"},
- { 3, 0x1a, "Tyco Electronics"},
- { 3, 0x9b, "Magis Works"},
- { 3, 0x1c, "Zettacom"},
- { 3, 0x9d, "Cogency Semiconductor"},
- { 3, 0x9e, "Chipcon AS"},
- { 3, 0x1f, "Aspex Technology"},
- { 3, 0x20, "F5 Networks"},
- { 3, 0xa1, "Programmable Silicon Solutions"},
- { 3, 0xa2, "ChipWrights"},
- { 3, 0x23, "Acorn Networks"},
- { 3, 0xa4, "Quicklogic"},
- { 3, 0x25, "Kingmax Semiconductor"},
- { 3, 0x26, "BOPS"},
- { 3, 0xa7, "Flasys"},
- { 3, 0xa8, "BitBlitz Communications"},
- { 3, 0x29, "eMemory Technology"},
- { 3, 0x2a, "Procket Networks"},
- { 3, 0xab, "Purple Ray"},
- { 3, 0x2c, "Trebia Networks"},
- { 3, 0xad, "Delta Electronics"},
- { 3, 0xae, "Onex Communications"},
- { 3, 0x2f, "Ample Communications"},
- { 3, 0xb0, "Memory Experts Intl"},
- { 3, 0x31, "Astute Networks"},
- { 3, 0x32, "Azanda Network Devices"},
- { 3, 0xb3, "Dibcom"},
- { 3, 0x34, "Tekmos"},
- { 3, 0xb5, "API NetWorks"},
- { 3, 0xb6, "Bay Microsystems"},
- { 3, 0x37, "Firecron"},
- { 3, 0x38, "Resonext Communications"},
- { 3, 0xb9, "Tachys Technologies"},
- { 3, 0xba, "Equator Technology"},
- { 3, 0x3b, "Concept Computer"},
- { 3, 0xbc, "SILCOM"},
- { 3, 0x3d, "3Dlabs"},
- { 3, 0x3e, "c?t Magazine"},
- { 3, 0xbf, "Sanera Systems"},
- { 3, 0x40, "Silicon Packets"},
- { 3, 0xc1, "Viasystems Group"},
- { 3, 0xc2, "Simtek"},
- { 3, 0x43, "Semicon Devices Singapore"},
- { 3, 0xc4, "Satron Handelsges"},
- { 3, 0x45, "Improv Systems"},
- { 3, 0x46, "INDUSYS"},
- { 3, 0xc7, "Corrent"},
- { 3, 0xc8, "Infrant Technologies"},
- { 3, 0x49, "Ritek Corp"},
- { 3, 0x4a, "empowerTel Networks"},
- { 3, 0xcb, "Hypertec"},
- { 3, 0x4c, "Cavium Networks"},
- { 3, 0xcd, "PLX Technology"},
- { 3, 0xce, "Massana Design"},
- { 3, 0x4f, "Intrinsity"},
- { 3, 0xd0, "Valence Semiconductor"},
- { 3, 0x51, "Terawave Communications"},
- { 3, 0x52, "IceFyre Semiconductor"},
- { 3, 0xd3, "Primarion"},
- { 3, 0x54, "Picochip Designs"},
- { 3, 0xd5, "Silverback Systems"},
- { 3, 0xd6, "Jade Star Technologies"},
- { 3, 0x57, "Pijnenburg Securealink"},
- { 3, 0x58, "takeMS International AG"},
- { 3, 0xd9, "Cambridge Silicon Radio"},
- { 3, 0xda, "Swissbit"},
- { 3, 0x5b, "Nazomi Communications"},
- { 3, 0xdc, "eWave System"},
- { 3, 0x5d, "Rockwell Collins"},
- { 3, 0x5e, "Picocel Co. (Paion)"},
- { 3, 0xdf, "Alphamosaic"},
- { 3, 0xe0, "Sandburst"},
- { 3, 0x61, "SiCon Video"},
- { 3, 0x62, "NanoAmp Solutions"},
- { 3, 0xe3, "Ericsson Technology"},
- { 3, 0x64, "PrairieComm"},
- { 3, 0xe5, "Mitac International"},
- { 3, 0xe6, "Layer N Networks"},
- { 3, 0x67, "MtekVision (Atsana)"},
- { 3, 0x68, "Allegro Networks"},
- { 3, 0xe9, "Marvell Semiconductors"},
- { 3, 0xea, "Netergy Microelectronic"},
- { 3, 0x6b, "NVIDIA"},
- { 3, 0xec, "Internet Machines"},
- { 3, 0x6d, "Peak Electronics"},
- { 3, 0x6e, "Litchfield Communication"},
- { 3, 0xef, "Accton Technology"},
- { 3, 0x70, "Teradiant Networks"},
- { 3, 0xf1, "Scaleo Chip"},
- { 3, 0xf2, "Cortina Systems"},
- { 3, 0x73, "RAM Components"},
- { 3, 0xf4, "Raqia Networks"},
- { 3, 0x75, "ClearSpeed"},
- { 3, 0x76, "Matsushita Battery"},
- { 3, 0xf7, "Xelerated"},
- { 3, 0xf8, "SimpleTech"},
- { 3, 0x79, "Utron Technology"},
- { 3, 0x7a, "Astec International"},
- { 3, 0xfb, "AVM"},
- { 3, 0x7c, "Redux Communications"},
- { 3, 0xfd, "Dot Hill Systems"},
- { 3, 0xfe, "TeraChip"},
- { 4, 0x01, "T-RAM"},
- { 4, 0x02, "Innovics Wireless"},
- { 4, 0x83, "Teknovus"},
- { 4, 0x04, "KeyEye Communications"},
- { 4, 0x85, "Runcom Technologies"},
- { 4, 0x86, "RedSwitch"},
- { 4, 0x07, "Dotcast"},
- { 4, 0x08, "Silicon Mountain Memory"},
- { 4, 0x89, "Signia Technologies"},
- { 4, 0x8a, "Pixim"},
- { 4, 0x0b, "Galazar Networks"},
- { 4, 0x8c, "White Electronic Designs"},
- { 4, 0x0d, "Patriot Scientific"},
- { 4, 0x0e, "Neoaxiom"},
- { 4, 0x8f, "3Y Power Technology"},
- { 4, 0x10, "Scaleo Chip"},
- { 4, 0x91, "Potentia Power Systems"},
- { 4, 0x92, "C-guys"},
- { 4, 0x13, "Digital Communications Technology"},
- { 4, 0x94, "Silicon-Based Technology"},
- { 4, 0x15, "Fulcrum Microsystems"},
- { 4, 0x16, "Positivo Informatica"},
- { 4, 0x97, "XIOtech"},
- { 4, 0x98, "PortalPlayer"},
- { 4, 0x19, "Zhiying Software"},
- { 4, 0x1a, "ParkerVision"},
- { 4, 0x9b, "Phonex Broadband"},
- { 4, 0x1c, "Skyworks Solutions"},
- { 4, 0x9d, "Entropic Communications"},
- { 4, 0x9e, "Pacific Force Technology"},
- { 4, 0x1f, "Zensys A/S"},
- { 4, 0x20, "Legend Silicon Corp."},
- { 4, 0xa1, "Sci-worx"},
- { 4, 0xa2, "SMSC (Standard Microsystems)"},
- { 4, 0x23, "Renesas Technology"},
- { 4, 0xa4, "Raza Microelectronics"},
- { 4, 0x25, "Phyworks"},
- { 4, 0x26, "MediaTek"},
- { 4, 0xa7, "Non-cents Productions"},
- { 4, 0xa8, "US Modular"},
- { 4, 0x29, "Wintegra"},
- { 4, 0x2a, "Mathstar"},
- { 4, 0xab, "StarCore"},
- { 4, 0x2c, "Oplus Technologies"},
- { 4, 0xad, "Mindspeed"},
- { 4, 0xae, "Just Young Computer"},
- { 4, 0x2f, "Radia Communications"},
- { 4, 0xb0, "OCZ"},
- { 4, 0x31, "Emuzed"},
- { 4, 0x32, "LOGIC Devices"},
- { 4, 0xb3, "Inphi"},
- { 4, 0x34, "Quake Technologies"},
- { 4, 0xb5, "Vixel"},
- { 4, 0xb6, "SolusTek"},
- { 4, 0x37, "Kongsberg Maritime"},
- { 4, 0x38, "Faraday Technology"},
- { 4, 0xb9, "Altium"},
- { 4, 0xba, "Insyte"},
- { 4, 0x3b, "ARM"},
- { 4, 0xbc, "DigiVision"},
- { 4, 0x3d, "Vativ Technologies"},
- { 4, 0x3e, "Endicott Interconnect Technologies"},
- { 4, 0xbf, "Pericom"},
- { 4, 0x40, "Bandspeed"},
- { 4, 0xc1, "LeWiz Communications"},
- { 4, 0xc2, "CPU Technology"},
- { 4, 0x43, "Ramaxel Technology"},
- { 4, 0xc4, "DSP Group"},
- { 4, 0x45, "Axis Communications"},
- { 4, 0x46, "Legacy Electronics"},
- { 4, 0xc7, "Chrontel"},
- { 4, 0xc8, "Powerchip Semiconductor"},
- { 4, 0x49, "MobilEye Technologies"},
- { 4, 0x4a, "Excel Semiconductor"},
- { 4, 0xcb, "A-DATA Technology"},
- { 4, 0x4c, "VirtualDigm"},
- { 4, 0xcd, "G Skill Intl"},
- { 4, 0xce, "Quanta Computer"},
- { 4, 0x4f, "Yield Microelectronics"},
- { 4, 0xd0, "Afa Technologies"},
- { 4, 0x51, "KINGBOX Technology Co."},
- { 4, 0x52, "Ceva"},
- { 4, 0xd3, "iStor Networks"},
- { 4, 0x54, "Advance Modules"},
- { 4, 0xd5, "Microsoft"},
- { 4, 0xd6, "Open-Silicon"},
- { 4, 0x57, "Goal Semiconductor"},
- { 4, 0x58, "ARC International"},
- { 4, 0xd9, "Simmtec"},
- { 4, 0xda, "Metanoia"},
- { 4, 0x5b, "Key Stream"},
- { 4, 0xdc, "Lowrance Electronics"},
- { 4, 0x5d, "Adimos"},
- { 4, 0x5e, "SiGe Semiconductor"},
- { 4, 0xdf, "Fodus Communications"},
- { 4, 0xe0, "Credence Systems Corp."},
- { 4, 0x61, "Genesis Microchip"},
- { 4, 0x62, "Vihana"},
- { 4, 0xe3, "WIS Technologies"},
- { 4, 0x64, "GateChange Technologies"},
- { 4, 0xe5, "High Density Devices AS"},
- { 4, 0xe6, "Synopsys"},
- { 4, 0x67, "Gigaram"},
- { 4, 0x68, "Enigma Semiconductor"},
- { 4, 0xe9, "Century Micro"},
- { 4, 0xea, "Icera Semiconductor"},
- { 4, 0x6b, "Mediaworks Integrated Systems"},
- { 4, 0xec, "O'Neil Product Development"},
- { 4, 0x6d, "Supreme Top Technology"},
- { 4, 0x6e, "MicroDisplay"},
- { 4, 0xef, "Team Group"},
- { 4, 0x70, "Sinett"},
- { 4, 0xf1, "Toshiba"},
- { 4, 0xf2, "Tensilica"},
- { 4, 0x73, "SiRF Technology"},
- { 4, 0xf4, "Bacoc"},
- { 4, 0x75, "SMaL Camera Technologies"},
- { 4, 0x76, "Thomson SC"},
- { 4, 0xf7, "Airgo Networks"},
- { 4, 0xf8, "Wisair"},
- { 4, 0x79, "SigmaTel"},
- { 4, 0x7a, "Arkados"},
- { 4, 0xfb, "Compete IT Co. KG"},
- { 4, 0x7c, "Eudar Technology"},
- { 4, 0xfd, "Focus Enhancements"},
- { 4, 0xfe, "Xyratex"},
- { 5, 0x01, "Specular Networks"},
- { 5, 0x02, "Patriot Memory (PDP Systems)"},
- { 5, 0x83, "U-Chip Technology Corp."},
- { 5, 0x04, "Silicon Optix"},
- { 5, 0x85, "Greenfield Networks"},
- { 5, 0x86, "CompuRAM"},
- { 5, 0x07, "Stargen"},
- { 5, 0x08, "NetCell"},
- { 5, 0x89, "Excalibrus Technologies"},
- { 5, 0x8a, "SCM Microsystems"},
- { 5, 0x0b, "Xsigo Systems"},
- { 5, 0x8c, "CHIPS & Systems"},
- { 5, 0x0d, "Tier"},
- { 5, 0x0e, "CWRL Labs"},
- { 5, 0x8f, "Teradici"},
- { 5, 0x10, "Gigaram"},
- { 5, 0x91, "g2 Microsystems"},
- { 5, 0x92, "PowerFlash Semiconductor"},
- { 5, 0x13, "P.A. Semi"},
- { 5, 0x94, "NovaTech Solutions, S.A."},
- { 5, 0x15, "c2 Microsystems"},
- { 5, 0x16, "Level5 Networks"},
- { 5, 0x97, "COS Memory AG"},
- { 5, 0x98, "Innovasic Semiconductor"},
- { 5, 0x19, "02IC Co."},
- { 5, 0x1a, "Tabula,"},
- { 5, 0x9b, "Crucial Technology"},
- { 5, 0x1c, "Chelsio Communications"},
- { 5, 0x9d, "Solarflare Communications"},
- { 5, 0x9e, "Xambala"},
- { 5, 0x1f, "EADS Astrium"},
- { 5, 0x20, "Terra Semiconductor"},
- { 5, 0xa1, "Imaging Works"},
- { 5, 0xa2, "Astute Networks"},
- { 5, 0x23, "Tzero"},
- { 5, 0xa4, "Emulex"},
- { 5, 0x25, "Power-One"},
- { 5, 0x26, "Pulse~LINK"},
- { 5, 0xa7, "Hon Hai Precision Industry"},
- { 5, 0xa8, "White Rock Networks"},
- { 5, 0x29, "Telegent Systems USA"},
- { 5, 0x2a, "Atrua Technologies"},
- { 5, 0xab, "Acbel Polytech"},
- { 5, 0x2c, "eRide"},
- { 5, 0xad, "ULi Electronics"},
- { 5, 0xae, "Magnum Semiconductor"},
- { 5, 0x2f, "neoOne Technology"},
- { 5, 0xb0, "Connex Technology"},
- { 5, 0x31, "Stream Processors"},
- { 5, 0x32, "Focus Enhancements"},
- { 5, 0xb3, "Telecis Wireless"},
- { 5, 0x34, "uNav Microelectronics"},
- { 5, 0xb5, "Tarari"},
- { 5, 0xb6, "Ambric"},
- { 5, 0x37, "Newport Media"},
- { 5, 0x38, "VMTS"},
- { 5, 0xb9, "Enuclia Semiconductor"},
- { 5, 0xba, "Virtium Technology"},
- { 5, 0x3b, "Solid State System Co."},
- { 5, 0xbc, "Kian Tech LLC"},
- { 5, 0x3d, "Artimi"},
- { 5, 0x3e, "Power Quotient International"},
- { 5, 0xbf, "Avago Technologies"},
- { 5, 0x40, "ADTechnology"},
- { 5, 0xc1, "Sigma Designs"},
- { 5, 0xc2, "SiCortex"},
- { 5, 0x43, "Ventura Technology Group"},
- { 5, 0xc4, "eASIC"},
- { 5, 0x45, "M.H.S. SAS"},
- { 5, 0x46, "Micro Star International"},
- { 5, 0xc7, "Rapport"},
- { 5, 0xc8, "Makway International"},
- { 5, 0x49, "Broad Reach Engineering Co."},
- { 5, 0x4a, "Semiconductor Mfg Intl Corp"},
- { 5, 0xcb, "SiConnect"},
- { 5, 0x4c, "FCI USA"},
- { 5, 0xcd, "Validity Sensors"},
- { 5, 0xce, "Coney Technology Co."},
- { 5, 0x4f, "Spans Logic"},
- { 5, 0xd0, "Neterion"},
- { 5, 0x51, "Qimonda"},
- { 5, 0x52, "New Japan Radio Co."},
- { 5, 0xd3, "Velogix"},
- { 5, 0x54, "Montalvo Systems"},
- { 5, 0xd5, "iVivity"},
- { 5, 0xd6, "Walton Chaintech"},
- { 5, 0x57, "AENEON"},
- { 5, 0x58, "Lorom Industrial Co."},
- { 5, 0xd9, "Radiospire Networks"},
- { 5, 0xda, "Sensio Technologies"},
- { 5, 0x5b, "Nethra Imaging"},
- { 5, 0xdc, "Hexon Technology Pte"},
- { 5, 0x5d, "CompuStocx (CSX)"},
- { 5, 0x5e, "Methode Electronics"},
- { 5, 0xdf, "Connect One"},
- { 5, 0xe0, "Opulan Technologies"},
- { 5, 0x61, "Septentrio NV"},
- { 5, 0x62, "Goldenmars Technology"},
- { 5, 0xe3, "Kreton"},
- { 5, 0x64, "Cochlear"},
- { 5, 0xe5, "Altair Semiconductor"},
- { 5, 0xe6, "NetEffect"},
- { 5, 0x67, "Spansion"},
- { 5, 0x68, "Taiwan Semiconductor Mfg"},
- { 5, 0xe9, "Emphany Systems"},
- { 5, 0xea, "ApaceWave Technologies"},
- { 5, 0x6b, "Mobilygen"},
- { 5, 0xec, "Tego"},
- { 5, 0x6d, "Cswitch"},
- { 5, 0x6e, "Haier (Beijing) IC Design Co."},
- { 5, 0xef, "MetaRAM"},
- { 5, 0x70, "Axel Electronics Co."},
- { 5, 0xf1, "Tilera"},
- { 5, 0xf2, "Aquantia"},
- { 5, 0x73, "Vivace Semiconductor"},
- { 5, 0xf4, "Redpine Signals"},
- { 5, 0x75, "Octalica"},
- { 5, 0x76, "InterDigital Communications"},
- { 5, 0xf7, "Avant Technology"},
- { 5, 0xf8, "Asrock"},
- { 5, 0x79, "Availink"},
- { 5, 0x7a, "Quartics"},
- { 5, 0xfb, "Element CXI"},
- { 5, 0x7c, "Innovaciones Microelectronicas"},
- { 5, 0xfd, "VeriSilicon Microelectronics"},
- { 5, 0xfe, "W5 Networks"},
- { 6, 0x01, "MOVEKING"},
- { 6, 0x02, "Mavrix Technology"},
- { 6, 0x83, "CellGuide"},
- { 6, 0x04, "Faraday Technology"},
- { 6, 0x85, "Diablo Technologies"},
- { 6, 0x86, "Jennic"},
- { 6, 0x07, "Octasic"},
- { 6, 0x08, "Molex"},
- { 6, 0x89, "3Leaf Networks"},
- { 6, 0x8a, "Bright Micron Technology"},
- { 6, 0x0b, "Netxen"},
- { 6, 0x8c, "NextWave Broadband"},
- { 6, 0x0d, "DisplayLink"},
- { 6, 0x0e, "ZMOS Technology"},
- { 6, 0x8f, "Tec-Hill"},
- { 6, 0x10, "Multigig"},
- { 6, 0x91, "Amimon"},
- { 6, 0x92, "Euphonic Technologies"},
- { 6, 0x13, "BRN Phoenix"},
- { 6, 0x94, "InSilica"},
- { 6, 0x15, "Ember"},
- { 6, 0x16, "Avexir Technologies"},
- { 6, 0x97, "Echelon"},
- { 6, 0x98, "Edgewater Computer Systems"},
- { 6, 0x19, "XMOS Semiconductor"},
- { 6, 0x1a, "GENUSION"},
- { 6, 0x9b, "Memory Corp NV"},
- { 6, 0x1c, "SiliconBlue Technologies"},
- { 6, 0x9d, "Rambus"},
- { 6, 0x9e, "Andes Technology"},
- { 6, 0x1f, "Coronis Systems"},
- { 6, 0x20, "Achronix Semiconductor"},
- { 6, 0xa1, "Siano Mobile Silicon"},
- { 6, 0xa2, "Semtech"},
- { 6, 0x23, "Pixelworks"},
- { 6, 0xa4, "Gaisler Research AB"},
- { 6, 0x25, "Teranetics"},
- { 6, 0x26, "Toppan Printing Co."},
- { 6, 0xa7, "Kingxcon"},
- { 6, 0xa8, "Silicon Integrated Systems"},
- { 6, 0x29, "I-O Data Device"},
- { 6, 0x2a, "NDS Americas"},
- { 6, 0xab, "Solomon Systech Limited"},
- { 6, 0x2c, "On Demand Microelectronics"},
- { 6, 0xad, "Amicus Wireless"},
- { 6, 0xae, "SMARDTV SNC"},
- { 6, 0x2f, "Comsys Communication"},
- { 6, 0xb0, "Movidia"},
- { 6, 0x31, "Javad GNSS"},
- { 6, 0x32, "Montage Technology Group"},
- { 6, 0xb3, "Trident Microsystems"},
- { 6, 0x34, "Super Talent"},
- { 6, 0xb5, "Optichron"},
- { 6, 0xb6, "Future Waves UK"},
- { 6, 0x37, "SiBEAM"},
- { 6, 0x38, "Inicore,"},
- { 6, 0xb9, "Virident Systems"},
- { 6, 0xba, "M2000"},
- { 6, 0x3b, "ZeroG Wireless"},
- { 6, 0xbc, "Gingle Technology Co."},
- { 6, 0x3d, "Space Micro"},
- { 6, 0x3e, "Wilocity"},
- { 6, 0xbf, "Novafora, Ic."},
- { 6, 0x40, "iKoa"},
- { 6, 0xc1, "ASint Technology"},
- { 6, 0xc2, "Ramtron"},
- { 6, 0x43, "Plato Networks"},
- { 6, 0xc4, "IPtronics AS"},
- { 6, 0x45, "Infinite-Memories"},
- { 6, 0x46, "Parade Technologies"},
- { 6, 0xc7, "Dune Networks"},
- { 6, 0xc8, "GigaDevice Semiconductor"},
- { 6, 0x49, "Modu"},
- { 6, 0x4a, "CEITEC"},
- { 6, 0xcb, "Northrop Grumman"},
- { 6, 0x4c, "XRONET"},
- { 6, 0xcd, "Sicon Semiconductor AB"},
- { 6, 0xce, "Atla Electronics Co."},
- { 6, 0x4f, "TOPRAM Technology"},
- { 6, 0xd0, "Silego Technology"},
- { 6, 0x51, "Kinglife"},
- { 6, 0x52, "Ability Industries"},
- { 6, 0xd3, "Silicon Power Computer & Communications"},
- { 6, 0x54, "Augusta Technology"},
- { 6, 0xd5, "Nantronics Semiconductors"},
- { 6, 0xd6, "Hilscher Gesellschaft"},
- { 6, 0x57, "Quixant"},
- { 6, 0x58, "Percello"},
- { 6, 0xd9, "NextIO"},
- { 6, 0xda, "Scanimetrics"},
- { 6, 0x5b, "FS-Semi Company"},
- { 6, 0xdc, "Infinera"},
- { 6, 0x5d, "SandForce"},
- { 6, 0x5e, "Lexar Media"},
- { 6, 0xdf, "Teradyne"},
- { 6, 0xe0, "Memory Exchange Corp."},
- { 6, 0x61, "Suzhou Smartek Electronics"},
- { 6, 0x62, "Avantium"},
- { 6, 0xe3, "ATP Electronics"},
- { 6, 0x64, "Valens Semiconductor"},
- { 6, 0xe5, "Agate Logic"},
- { 6, 0xe6, "Netronome"},
- { 6, 0x67, "Zenverge"},
- { 6, 0x68, "N-trig"},
- { 6, 0xe9, "SanMax Technologies"},
- { 6, 0xea, "Contour Semiconductor"},
- { 6, 0x6b, "TwinMOS"},
- { 6, 0xec, "Silicon Systems"},
- { 6, 0x6d, "V-Color Technology"},
- { 6, 0x6e, "Certicom"},
- { 6, 0xef, "JSC ICC Milandr"},
- { 6, 0x70, "PhotoFast Global"},
- { 6, 0xf1, "InnoDisk"},
- { 6, 0xf2, "Muscle Power"},
- { 6, 0x73, "Energy Micro"},
- { 6, 0xf4, "Innofidei"},
- { 9, 0xff, ""}
+static struct spd_jedec_manufacturer jep106[] = {
+ { 0, 0x01, "AMD"},
+ { 0, 0x02, "AMI"},
+ { 0, 0x83, "Fairchild"},
+ { 0, 0x04, "Fujitsu"},
+// { 0, 0x85, "GTE"},
+ { 0, 0x86, "Harris"},
+ { 0, 0x07, "Hitachi"},
+ { 0, 0x08, "Inmos"},
+ { 0, 0x89, "Intel"},
+ { 0, 0x8a, "I.T.T."},
+ { 0, 0x0b, "Intersil"},
+ { 0, 0x8c, "Monolithic Memories"},
+ { 0, 0x0d, "Mostek"},
+ { 0, 0x0e, "Freescale"},
+ { 0, 0x8f, "National"},
+ { 0, 0x10, "NEC"},
+ { 0, 0x91, "RCA"},
+ { 0, 0x92, "Raytheon"},
+ { 0, 0x13, "Conexant"},
+// { 0, 0x94, "Seeq"},
+ { 0, 0x15, "NXP"},
+ { 0, 0x16, "Synertek"},
+ { 0, 0x97, "Texas Instruments"},
+ { 0, 0x98, "Toshiba"},
+ { 0, 0x19, "Xicor"},
+ { 0, 0x1a, "Zilog"},
+// { 0, 0x9b, "Eurotechnique"},
+ { 0, 0x1c, "Mitsubishi"},
+ { 0, 0x9d, "Lucent (AT&T)"},
+// { 0, 0x9e, "Exel"},
+ { 0, 0x1f, "Atmel"},
+ { 0, 0x20, "SGS/Thomson"},
+// { 0, 0xa1, "Lattice Semi."},
+ { 0, 0xa2, "NCR"},
+// { 0, 0x23, "Wafer Scale Integration"},
+ { 0, 0xa4, "IBM"},
+ { 0, 0x25, "Tristar"},
+// { 0, 0x26, "Visic"},
+ { 0, 0xa7, "Intl. CMOS Technology"},
+// { 0, 0xa8, "SSSI"},
+ { 0, 0x29, "MicrochipTechnology"},
+// { 0, 0x2a, "Ricoh"},
+// { 0, 0xab, "VLSI"},
+ { 0, 0x2c, "Micron"},
+ { 0, 0xad, "Hynix"},
+ { 0, 0xae, "OKI Semiconductor"},
+// { 0, 0x2f, "ACTEL"},
+ { 0, 0xb0, "Sharp"},
+ { 0, 0x31, "Catalyst"},
+ { 0, 0x32, "Panasonic"},
+ { 0, 0xb3, "IDT"},
+ { 0, 0x34, "Cypress"},
+ { 0, 0xb5, "DEC"},
+ { 0, 0xb6, "LSI Logic"},
+// { 0, 0x37, "Zarlink (Plessey)"},
+ { 0, 0x38, "UTMC"},
+// { 0, 0xb9, "Thinking Machine"},
+ { 0, 0xba, "Thomson CSF"},
+// { 0, 0x3b, "Integrated CMOS (Vertex)"},
+// { 0, 0xbc, "Honeywell"},
+ { 0, 0x3d, "Tektronix"},
+// { 0, 0x3e, "Oracle"},
+// { 0, 0xbf, "Silicon Storage Technology"},
+ { 0, 0x40, "ProMos/Mosel"},
+ { 0, 0xc1, "Infineon"},
+// { 0, 0xc2, "Macronix"},
+ { 0, 0x43, "Xerox"},
+// { 0, 0xc4, "Plus Logic"},
+ { 0, 0x45, "SanDisk"},
+// { 0, 0x46, "Elan Circuit Tech."},
+// { 0, 0xc7, "European Silicon Str."},
+ { 0, 0xc8, "Apple Computer"},
+ { 0, 0x49, "Xilinx"},
+ { 0, 0x4a, "Compaq"},
+// { 0, 0xcb, "Protocol Engines"},
+// { 0, 0x4c, "SCI"},
+ { 0, 0xcd, "Seiko Instruments"},
+ { 0, 0xce, "Samsung"},
+// { 0, 0x4f, "I3 Design System"},
+// { 0, 0xd0, "Klic"},
+// { 0, 0x51, "Crosspoint Solutions"},
+// { 0, 0x52, "Alliance Semiconductor"},
+// { 0, 0xd3, "Tandem"},
+ { 0, 0x54, "Hewlett-Packard"},
+ { 0, 0xd5, "Integrated Silicon Solutions"},
+// { 0, 0xd6, "Brooktree"},
+// { 0, 0x57, "New Media"},
+// { 0, 0x58, "MHS Electronic"},
+// { 0, 0xd9, "Performance Semi."},
+ { 0, 0xda, "Winbond Electronic"},
+// { 0, 0x5b, "Kawasaki Steel"},
+// { 0, 0xdc, "Bright Micro"},
+// { 0, 0x5d, "TECMAR"},
+ { 0, 0x5e, "Exar"},
+// { 0, 0xdf, "PCMCIA"},
+ { 0, 0xe0, "LG"},
+// { 0, 0x61, "Northern Telecom"},
+ { 0, 0x62, "Sanyo"},
+// { 0, 0xe3, "Array Microsystems"},
+// { 0, 0x64, "Crystal Semiconductor"},
+ { 0, 0xe5, "Analog Devices"},
+// { 0, 0xe6, "PMC-Sierra"},
+// { 0, 0x67, "Asparix"},
+// { 0, 0x68, "Convex Computer"},
+// { 0, 0xe9, "Quality Semiconductor"},
+// { 0, 0xea, "Nimbus Technology"},
+// { 0, 0x6b, "Transwitch"},
+// { 0, 0xec, "Micronas (ITT Intermetall)"},
+ { 0, 0x6d, "Cannon"},
+// { 0, 0x6e, "Altera"},
+// { 0, 0xef, "NEXCOM"},
+// { 0, 0x70, "QUALCOMM"},
+ { 0, 0xf1, "Sony"},
+// { 0, 0xf2, "Cray Research"},
+// { 0, 0x73, "AMS(Austria Micro)"},
+// { 0, 0xf4, "Vitesse"},
+// { 0, 0x75, "Aster Electronics"},
+// { 0, 0x76, "Bay Networks (Synoptic)"},
+// { 0, 0xf7, "Zentrum/ZMD"},
+// { 0, 0xf8, "TRW"},
+// { 0, 0x79, "Thesys"},
+// { 0, 0x7a, "Solbourne Computer"},
+ { 0, 0xfb, "Allied-Signal"},
+ { 0, 0x7c, "Dialog"},
+ { 0, 0xfd, "Media Vision"},
+// { 0, 0xfe, "Numonyx"},
+ { 1, 0x01, "Cirrus Logic"},
+ { 1, 0x02, "National Instruments"},
+// { 1, 0x83, "ILC Data Device"},
+// { 1, 0x04, "Alcatel Mietec"},
+// { 1, 0x85, "Micro Linear"},
+// { 1, 0x86, "Univ. of NC"},
+// { 1, 0x07, "JTAG Technologies"},
+// { 1, 0x08, "BAE Systems (Loral)"},
+// { 1, 0x89, "Nchip"},
+// { 1, 0x8a, "Galileo Tech"},
+// { 1, 0x0b, "Bestlink Systems"},
+// { 1, 0x8c, "Graychip"},
+// { 1, 0x0d, "GENNUM"},
+// { 1, 0x0e, "VideoLogic"},
+// { 1, 0x8f, "Robert Bosch"},
+// { 1, 0x10, "Chip Express"},
+ { 1, 0x91, "DATARAM"},
+// { 1, 0x92, "United Microelectronics Corp."},
+// { 1, 0x13, "TCSI"},
+ { 1, 0x94, "Smart Modular"},
+// { 1, 0x15, "Hughes Aircraft"},
+// { 1, 0x16, "Lanstar Semiconductor"},
+// { 1, 0x97, "Qlogic"},
+ { 1, 0x98, "Kingston"},
+// { 1, 0x19, "Music Semi"},
+// { 1, 0x1a, "Ericsson Components"},
+// { 1, 0x9b, "SpaSE"},
+// { 1, 0x1c, "Eon Silicon Devices"},
+// { 1, 0x9d, "Programmable Micro Corp"},
+// { 1, 0x9e, "DoD"},
+// { 1, 0x1f, "Integ. Memories Tech."},
+// { 1, 0x20, "Corollary"},
+// { 1, 0xa1, "Dallas Semiconductor"},
+// { 1, 0xa2, "Omnivision"},
+// { 1, 0x23, "EIV(Switzerland)"},
+// { 1, 0xa4, "Novatel Wireless"},
+// { 1, 0x25, "Zarlink (Mitel)"},
+// { 1, 0x26, "Clearpoint"},
+// { 1, 0xa7, "Cabletron"},
+// { 1, 0xa8, "STEC (Silicon Tech)"},
+// { 1, 0x29, "Vanguard"},
+// { 1, 0x2a, "Hagiwara Sys-Com"},
+// { 1, 0xab, "Vantis"},
+// { 1, 0x2c, "Celestica"},
+// { 1, 0xad, "Century"},
+// { 1, 0xae, "Hal Computers"},
+// { 1, 0x2f, "Rohm Company"},
+// { 1, 0xb0, "Juniper Networks"},
+// { 1, 0x31, "Libit Signal Processing"},
+ { 1, 0x32, "Mushkin"},
+// { 1, 0xb3, "Tundra Semiconductor"},
+ { 1, 0x34, "Adaptec"},
+// { 1, 0xb5, "LightSpeed Semi."},
+// { 1, 0xb6, "ZSP Corp."},
+// { 1, 0x37, "AMIC Technology"},
+// { 1, 0x38, "Adobe Systems"},
+// { 1, 0xb9, "Dynachip"},
+ { 1, 0xba, "PNY"},
+// { 1, 0x3b, "Newport Digital"},
+// { 1, 0xbc, "MMC Networks"},
+// { 1, 0x3d, "T Square"},
+// { 1, 0x3e, "Seiko Epson"},
+// { 1, 0xbf, "Broadcom"},
+// { 1, 0x40, "Viking Components"},
+// { 1, 0xc1, "V3 Semiconductor"},
+// { 1, 0xc2, "Flextronics (Orbit Semiconductor)"},
+// { 1, 0x43, "Suwa Electronics"},
+ { 1, 0xc4, "Transmeta"},
+ { 1, 0x45, "Micron CMS"},
+// { 1, 0x46, "American Computer & Digital Components"},
+// { 1, 0xc7, "Enhance 3000"},
+ { 1, 0xc8, "Tower Semiconductor"},
+// { 1, 0x49, "CPU Design"},
+// { 1, 0x4a, "Price Point"},
+ { 1, 0xcb, "Maxim Integrated Product"},
+// { 1, 0x4c, "Tellabs"},
+// { 1, 0xcd, "Centaur Technology"},
+ { 1, 0xce, "Unigen"},
+ { 1, 0x4f, "Transcend"},
+ { 1, 0xd0, "Memory Card"},
+// { 1, 0x51, "CKD"},
+// { 1, 0x52, "Capital Instruments"},
+// { 1, 0xd3, "Aica Kogyo"},
+// { 1, 0x54, "Linvex Technology"},
+ { 1, 0xd5, "MSC"},
+// { 1, 0xd6, "AKM Company"},
+// { 1, 0x57, "Dynamem"},
+// { 1, 0x58, "NERA ASA"},
+// { 1, 0xd9, "GSI Technology"},
+ { 1, 0xda, "Dane-Elec"},
+// { 1, 0x5b, "Acorn Computers"},
+// { 1, 0xdc, "Lara Technology"},
+// { 1, 0x5d, "Oak Technology"},
+ { 1, 0x5e, "Itec Memory"},
+// { 1, 0xdf, "Tanisys Technology"},
+// { 1, 0xe0, "Truevision"},
+ { 1, 0x61, "Wintec"},
+// { 1, 0x62, "Super PC Memory"},
+// { 1, 0xe3, "MGV Memory"},
+// { 1, 0x64, "Galvantech"},
+// { 1, 0xe5, "Gadzoox Networks"},
+// { 1, 0xe6, "Multi Dimensional Cons."},
+// { 1, 0x67, "GateField"},
+ { 1, 0x68, "Integrated Memory System"},
+// { 1, 0xe9, "Triscend"},
+// { 1, 0xea, "XaQti"},
+// { 1, 0x6b, "Goldenram"},
+// { 1, 0xec, "Clear Logic"},
+// { 1, 0x6d, "Cimaron Communications"},
+// { 1, 0x6e, "Nippon Steel Semi. Corp."},
+// { 1, 0xef, "Advantage Memory"},
+// { 1, 0x70, "AMCC"},
+ { 1, 0xf1, "LeCroy"},
+// { 1, 0xf2, "Yamaha"},
+// { 1, 0x73, "Digital Microwave"},
+// { 1, 0xf4, "NetLogic Microsystems"},
+// { 1, 0x75, "MIMOS Semiconductor"},
+// { 1, 0x76, "Advanced Fibre"},
+// { 1, 0xf7, "BF Goodrich Data."},
+// { 1, 0xf8, "Epigram"},
+// { 1, 0x79, "Acbel Polytech"},
+ { 1, 0x7a, "Apacer Technology"},
+// { 1, 0xfb, "Admor Memory"},
+ { 1, 0x7c, "FOXCONN"},
+// { 1, 0xfd, "Quadratics Superconductor"},
+// { 1, 0xfe, "3COM"},
+// { 2, 0x01, "Camintonn"},
+// { 2, 0x02, "ISOA"},
+// { 2, 0x83, "Agate Semiconductor"},
+// { 2, 0x04, "ADMtek"},
+// { 2, 0x85, "HYPERTEC"},
+// { 2, 0x86, "Adhoc Technologies"},
+// { 2, 0x07, "MOSAID Technologies"},
+// { 2, 0x08, "Ardent Technologies"},
+// { 2, 0x89, "Switchcore"},
+// { 2, 0x8a, "Cisco Systems"},
+// { 2, 0x0b, "Allayer Technologies"},
+// { 2, 0x8c, "WorkX AG (Wichman)"},
+// { 2, 0x0d, "Oasis Semiconductor"},
+// { 2, 0x0e, "Novanet Semiconductor"},
+// { 2, 0x8f, "E-M Solutions"},
+// { 2, 0x10, "Power General"},
+// { 2, 0x91, "Advanced Hardware Arch."},
+// { 2, 0x92, "Inova Semiconductors"},
+// { 2, 0x13, "Telocity"},
+// { 2, 0x94, "Delkin Devices"},
+// { 2, 0x15, "Symagery Microsystems"},
+// { 2, 0x16, "C-Port"},
+// { 2, 0x97, "SiberCore Technologies"},
+// { 2, 0x98, "Southland Microsystems"},
+// { 2, 0x19, "Malleable Technologies"},
+// { 2, 0x1a, "Kendin Communications"},
+// { 2, 0x9b, "Great Technology Microcomputer"},
+// { 2, 0x1c, "Sanmina"},
+// { 2, 0x9d, "HADCO"},
+ { 2, 0x9e, "Corsair"},
+// { 2, 0x1f, "Actrans System"},
+// { 2, 0x20, "ALPHA Technologies"},
+// { 2, 0xa1, "Silicon Laboratories (Cygnal)"},
+// { 2, 0xa2, "Artesyn Technologies"},
+// { 2, 0x23, "Align Manufacturing"},
+// { 2, 0xa4, "Peregrine Semiconductor"},
+// { 2, 0x25, "Chameleon Systems"},
+// { 2, 0x26, "Aplus Flash Technology"},
+ { 2, 0xa7, "MIPS Technologies"},
+// { 2, 0xa8, "Chrysalis ITS"},
+// { 2, 0x29, "ADTEC"},
+ { 2, 0x2a, "Kentron Technologies"},
+// { 2, 0xab, "Win Technologies"},
+// { 2, 0x2c, "Tachyon Semiconductor (ASIC)"},
+// { 2, 0xad, "Extreme Packet Devices"},
+// { 2, 0xae, "RF Micro Devices"},
+ { 2, 0x2f, "Siemens AG"},
+// { 2, 0xb0, "Sarnoff"},
+// { 2, 0x31, "Itautec SA"},
+// { 2, 0x32, "Radiata"},
+// { 2, 0xb3, "Benchmark Elect. (AVEX)"},
+// { 2, 0x34, "Legend"},
+ { 2, 0xb5, "SpecTek"},
+// { 2, 0xb6, "Hi/fn"},
+// { 2, 0x37, "Enikia"},
+// { 2, 0x38, "SwitchOn Networks"},
+// { 2, 0xb9, "AANetcom"},
+// { 2, 0xba, "Micro Memory Bank"},
+ { 2, 0x3b, "ESS Technology"},
+// { 2, 0xbc, "Virata"},
+// { 2, 0x3d, "Excess Bandwidth"},
+// { 2, 0x3e, "West Bay Semiconductor"},
+// { 2, 0xbf, "DSP Group"},
+// { 2, 0x40, "Newport Communications"},
+// { 2, 0xc1, "Chip2Chip"},
+// { 2, 0xc2, "Phobos"},
+// { 2, 0x43, "Intellitech"},
+// { 2, 0xc4, "Nordic VLSI ASA"},
+// { 2, 0x45, "Ishoni Networks"},
+// { 2, 0x46, "Silicon Spice"},
+// { 2, 0xc7, "Alchemy Semiconductor"},
+ { 2, 0xc8, "Agilent Technologies"},
+// { 2, 0x49, "Centillium Communications"},
+// { 2, 0x4a, "W.L. Gore"},
+// { 2, 0xcb, "HanBit Electronics"},
+// { 2, 0x4c, "GlobeSpan"},
+// { 2, 0xcd, "Element 14"},
+// { 2, 0xce, "Pycon"},
+// { 2, 0x4f, "Saifun Semiconductors"},
+// { 2, 0xd0, "Sibyte,"},
+// { 2, 0x51, "MetaLink Technologies"},
+// { 2, 0x52, "Feiya Technology"},
+// { 2, 0xd3, "I & C Technology"},
+// { 2, 0x54, "Shikatronics"},
+// { 2, 0xd5, "Elektrobit"},
+// { 2, 0xd6, "Megic"},
+// { 2, 0x57, "Com-Tier"},
+// { 2, 0x58, "Malaysia Micro Solutions"},
+// { 2, 0xd9, "Hyperchip"},
+// { 2, 0xda, "Gemstone Communications"},
+// { 2, 0x5b, "Anadigm (Anadyne)"},
+// { 2, 0xdc, "3ParData"},
+// { 2, 0x5d, "Mellanox Technologies"},
+// { 2, 0x5e, "Tenx Technologies"},
+// { 2, 0xdf, "Helix AG"},
+// { 2, 0xe0, "Domosys"},
+// { 2, 0x61, "Skyup Technology"},
+// { 2, 0x62, "HiNT"},
+// { 2, 0xe3, "Chiaro"},
+ { 2, 0x64, "MDT"},
+// { 2, 0xe5, "Exbit Technology A/S"},
+// { 2, 0xe6, "Integrated Technology Express"},
+// { 2, 0x67, "AVED Memory"},
+// { 2, 0x68, "Legerity"},
+// { 2, 0xe9, "Jasmine Networks"},
+// { 2, 0xea, "Caspian Networks"},
+// { 2, 0x6b, "nCUBE"},
+// { 2, 0xec, "Silicon Access Networks"},
+// { 2, 0x6d, "FDK"},
+// { 2, 0x6e, "High Bandwidth Access"},
+// { 2, 0xef, "MultiLink Technology"},
+// { 2, 0x70, "BRECIS"},
+// { 2, 0xf1, "World Wide Packets"},
+// { 2, 0xf2, "APW"},
+// { 2, 0x73, "Chicory Systems"},
+// { 2, 0xf4, "Xstream Logic"},
+// { 2, 0x75, "Fast-Chip"},
+// { 2, 0x76, "Zucotto Wireless"},
+// { 2, 0xf7, "Realchip"},
+// { 2, 0xf8, "Galaxy Power"},
+// { 2, 0x79, "eSilicon"},
+// { 2, 0x7a, "Morphics Technology"},
+// { 2, 0xfb, "Accelerant Networks"},
+// { 2, 0x7c, "Silicon Wave"},
+// { 2, 0xfd, "SandCraft"},
+ { 2, 0xfe, "Elpida"},
+// { 3, 0x01, "Solectron"},
+ { 3, 0x02, "Optosys Technologies"},
+ { 3, 0x83, "Buffalo"},
+// { 3, 0x04, "TriMedia Technologies"},
+// { 3, 0x85, "Cyan Technologies"},
+// { 3, 0x86, "Global Locate"},
+// { 3, 0x07, "Optillion"},
+// { 3, 0x08, "Terago Communications"},
+// { 3, 0x89, "Ikanos Communications"},
+ { 3, 0x8a, "Princeton"},
+ { 3, 0x0b, "Nanya"},
+// { 3, 0x8c, "Elite Flash Storage"},
+// { 3, 0x0d, "Mysticom"},
+// { 3, 0x0e, "LightSand Communications"},
+ { 3, 0x8f, "ATI"},
+// { 3, 0x10, "Agere Systems"},
+// { 3, 0x91, "NeoMagic"},
+// { 3, 0x92, "AuroraNetics"},
+// { 3, 0x13, "Golden Empire"},
+ { 3, 0x94, "Mushkin"},
+// { 3, 0x15, "Tioga Technologies"},
+ { 3, 0x16, "Netlist"},
+// { 3, 0x97, "TeraLogic"},
+// { 3, 0x98, "Cicada Semiconductor"},
+ { 3, 0x19, "Centon"},
+ { 3, 0x1a, "Tyco Electronics"},
+// { 3, 0x9b, "Magis Works"},
+// { 3, 0x1c, "Zettacom"},
+// { 3, 0x9d, "Cogency Semiconductor"},
+// { 3, 0x9e, "Chipcon AS"},
+// { 3, 0x1f, "Aspex Technology"},
+// { 3, 0x20, "F5 Networks"},
+// { 3, 0xa1, "Programmable Silicon Solutions"},
+// { 3, 0xa2, "ChipWrights"},
+// { 3, 0x23, "Acorn Networks"},
+// { 3, 0xa4, "Quicklogic"},
+ { 3, 0x25, "Kingmax"},
+// { 3, 0x26, "BOPS"},
+// { 3, 0xa7, "Flasys"},
+// { 3, 0xa8, "BitBlitz Communications"},
+ { 3, 0x29, "eMemory Technology"},
+// { 3, 0x2a, "Procket Networks"},
+// { 3, 0xab, "Purple Ray"},
+// { 3, 0x2c, "Trebia Networks"},
+// { 3, 0xad, "Delta Electronics"},
+// { 3, 0xae, "Onex Communications"},
+// { 3, 0x2f, "Ample Communications"},
+ { 3, 0xb0, "Memory Experts"},
+// { 3, 0x31, "Astute Networks"},
+// { 3, 0x32, "Azanda Network Devices"},
+// { 3, 0xb3, "Dibcom"},
+// { 3, 0x34, "Tekmos"},
+// { 3, 0xb5, "API NetWorks"},
+// { 3, 0xb6, "Bay Microsystems"},
+// { 3, 0x37, "Firecron"},
+// { 3, 0x38, "Resonext Communications"},
+// { 3, 0xb9, "Tachys Technologies"},
+// { 3, 0xba, "Equator Technology"},
+// { 3, 0x3b, "Concept Computer"},
+// { 3, 0xbc, "SILCOM"},
+// { 3, 0x3d, "3Dlabs"},
+// { 3, 0x3e, "c’t Magazine"},
+// { 3, 0xbf, "Sanera Systems"},
+// { 3, 0x40, "Silicon Packets"},
+ { 3, 0xc1, "Viasystems Group"},
+ { 3, 0xc2, "Simtek"},
+// { 3, 0x43, "Semicon Devices Singapore"},
+// { 3, 0xc4, "Satron Handelsges"},
+// { 3, 0x45, "Improv Systems"},
+// { 3, 0x46, "INDUSYS"},
+// { 3, 0xc7, "Corrent"},
+// { 3, 0xc8, "Infrant Technologies"},
+// { 3, 0x49, "Ritek Corp"},
+// { 3, 0x4a, "empowerTel Networks"},
+// { 3, 0xcb, "Hypertec"},
+// { 3, 0x4c, "Cavium Networks"},
+ { 3, 0xcd, "PLX Technology"},
+// { 3, 0xce, "Massana Design"},
+// { 3, 0x4f, "Intrinsity"},
+// { 3, 0xd0, "Valence Semiconductor"},
+// { 3, 0x51, "Terawave Communications"},
+// { 3, 0x52, "IceFyre Semiconductor"},
+// { 3, 0xd3, "Primarion"},
+// { 3, 0x54, "Picochip Designs"},
+// { 3, 0xd5, "Silverback Systems"},
+ { 3, 0xd6, "Jade Star"},
+// { 3, 0x57, "Pijnenburg Securealink"},
+ { 3, 0x58, "takeMS"},
+// { 3, 0xd9, "Cambridge Silicon Radio"},
+ { 3, 0xda, "Swissbit"},
+// { 3, 0x5b, "Nazomi Communications"},
+// { 3, 0xdc, "eWave System"},
+// { 3, 0x5d, "Rockwell Collins"},
+// { 3, 0x5e, "Picocel (Paion)"},
+// { 3, 0xdf, "Alphamosaic"},
+// { 3, 0xe0, "Sandburst"},
+// { 3, 0x61, "SiCon Video"},
+// { 3, 0x62, "NanoAmp Solutions"},
+// { 3, 0xe3, "Ericsson Technology"},
+// { 3, 0x64, "PrairieComm"},
+ { 3, 0xe5, "Mitac International"},
+// { 3, 0xe6, "Layer N Networks"},
+// { 3, 0x67, "MtekVision (Atsana)"},
+// { 3, 0x68, "Allegro Networks"},
+// { 3, 0xe9, "Marvell Semiconductors"},
+// { 3, 0xea, "Netergy Microelectronic"},
+ { 3, 0x6b, "nVidia"},
+// { 3, 0xec, "Internet Machines"},
+// { 3, 0x6d, "Peak Electronics"},
+// { 3, 0x6e, "Litchfield Communication"},
+ { 3, 0xef, "Accton"},
+// { 3, 0x70, "Teradiant Networks"},
+// { 3, 0xf1, "Scaleo Chip"},
+// { 3, 0xf2, "Cortina Systems"},
+ { 3, 0x73, "RAM Components"},
+// { 3, 0xf4, "Raqia Networks"},
+// { 3, 0x75, "ClearSpeed"},
+// { 3, 0x76, "Matsushita Battery"},
+// { 3, 0xf7, "Xelerated"},
+// { 3, 0xf8, "SimpleTech"},
+ { 3, 0x79, "Utron"},
+// { 3, 0x7a, "Astec International"},
+// { 3, 0xfb, "AVM"},
+// { 3, 0x7c, "Redux Communications"},
+// { 3, 0xfd, "Dot Hill Systems"},
+ { 3, 0xfe, "TeraChip"},
+ { 4, 0x01, "T-RAM"},
+// { 4, 0x02, "Innovics Wireless"},
+// { 4, 0x83, "Teknovus"},
+// { 4, 0x04, "KeyEye Communications"},
+// { 4, 0x85, "Runcom Technologies"},
+// { 4, 0x86, "RedSwitch"},
+// { 4, 0x07, "Dotcast"},
+ { 4, 0x08, "Silicon Mountain Memory"},
+// { 4, 0x89, "Signia Technologies"},
+// { 4, 0x8a, "Pixim"},
+// { 4, 0x0b, "Galazar Networks"},
+// { 4, 0x8c, "White Electronic Designs"},
+// { 4, 0x0d, "Patriot Scientific"},
+// { 4, 0x0e, "Neoaxiom"},
+// { 4, 0x8f, "3Y Power Technology"},
+ { 4, 0x10, "Scaleo Chip"},
+// { 4, 0x91, "Potentia Power Systems"},
+// { 4, 0x92, "C-guys"},
+// { 4, 0x13, "Digital Communications Technology"},
+// { 4, 0x94, "Silicon-Based Technology"},
+// { 4, 0x15, "Fulcrum Microsystems"},
+// { 4, 0x16, "Positivo Informatica"},
+// { 4, 0x97, "XIOtech"},
+// { 4, 0x98, "PortalPlayer"},
+// { 4, 0x19, "Zhiying Software"},
+// { 4, 0x1a, "ParkerVision"},
+// { 4, 0x9b, "Phonex Broadband"},
+// { 4, 0x1c, "Skyworks Solutions"},
+// { 4, 0x9d, "Entropic Communications"},
+// { 4, 0x9e, "Pacific Force Technology"},
+// { 4, 0x1f, "Zensys A/S"},
+// { 4, 0x20, "Legend Silicon Corp."},
+// { 4, 0xa1, "Sci-worx"},
+// { 4, 0xa2, "SMSC (Standard Microsystems)"},
+ { 4, 0x23, "Renesas"},
+// { 4, 0xa4, "Raza Microelectronics"},
+// { 4, 0x25, "Phyworks"},
+// { 4, 0x26, "MediaTek"},
+// { 4, 0xa7, "Non-cents Productions"},
+// { 4, 0xa8, "US Modular"},
+// { 4, 0x29, "Wintegra"},
+// { 4, 0x2a, "Mathstar"},
+// { 4, 0xab, "StarCore"},
+// { 4, 0x2c, "Oplus Technologies"},
+// { 4, 0xad, "Mindspeed"},
+// { 4, 0xae, "Just Young Computer"},
+// { 4, 0x2f, "Radia Communications"},
+ { 4, 0xb0, "OCZ"},
+// { 4, 0x31, "Emuzed"},
+// { 4, 0x32, "LOGIC Devices"},
+// { 4, 0xb3, "Inphi"},
+// { 4, 0x34, "Quake Technologies"},
+// { 4, 0xb5, "Vixel"},
+// { 4, 0xb6, "SolusTek"},
+// { 4, 0x37, "Kongsberg Maritime"},
+// { 4, 0x38, "Faraday Technology"},
+ { 4, 0xb9, "Altium"},
+// { 4, 0xba, "Insyte"},
+ { 4, 0x3b, "ARM"},
+// { 4, 0xbc, "DigiVision"},
+// { 4, 0x3d, "Vativ Technologies"},
+// { 4, 0x3e, "Endicott Interconnect Technologies"},
+ { 4, 0xbf, "Pericom"},
+// { 4, 0x40, "Bandspeed"},
+// { 4, 0xc1, "LeWiz Communications"},
+// { 4, 0xc2, "CPU Technology"},
+ { 4, 0x43, "Ramaxel"},
+// { 4, 0xc4, "DSP Group"},
+// { 4, 0x45, "Axis Communications"},
+ { 4, 0x46, "Legacy Electronics"},
+// { 4, 0xc7, "Chrontel"},
+// { 4, 0xc8, "Powerchip Semiconductor"},
+// { 4, 0x49, "MobilEye Technologies"},
+ { 4, 0x4a, "Excel Semiconductor"},
+ { 4, 0xcb, "A-DATA"},
+// { 4, 0x4c, "VirtualDigm"},
+ { 4, 0xcd, "G.Skill"},
+// { 4, 0xce, "Quanta Computer"},
+// { 4, 0x4f, "Yield Microelectronics"},
+// { 4, 0xd0, "Afa Technologies"},
+ { 4, 0x51, "Kingbox"},
+// { 4, 0x52, "Ceva"},
+// { 4, 0xd3, "iStor Networks"},
+// { 4, 0x54, "Advance Modules"},
+ { 4, 0xd5, "Microsoft"},
+// { 4, 0xd6, "Open-Silicon"},
+// { 4, 0x57, "Goal Semiconductor"},
+// { 4, 0x58, "ARC International"},
+ { 4, 0xd9, "Simmtec"},
+// { 4, 0xda, "Metanoia"},
+// { 4, 0x5b, "Key Stream"},
+// { 4, 0xdc, "Lowrance Electronics"},
+// { 4, 0x5d, "Adimos"},
+// { 4, 0x5e, "SiGe Semiconductor"},
+// { 4, 0xdf, "Fodus Communications"},
+// { 4, 0xe0, "Credence Systems Corp."},
+// { 4, 0x61, "Genesis Microchip"},
+// { 4, 0x62, "Vihana"},
+// { 4, 0xe3, "WIS Technologies"},
+// { 4, 0x64, "GateChange Technologies"},
+// { 4, 0xe5, "High Density Devices AS"},
+// { 4, 0xe6, "Synopsys"},
+// { 4, 0x67, "Gigaram"},
+// { 4, 0x68, "Enigma Semiconductor"},
+// { 4, 0xe9, "Century Micro"},
+// { 4, 0xea, "Icera Semiconductor"},
+// { 4, 0x6b, "Mediaworks Integrated Systems"},
+// { 4, 0xec, "O’Neil Product Development"},
+// { 4, 0x6d, "Supreme Top Technology"},
+// { 4, 0x6e, "MicroDisplay"},
+ { 4, 0xef, "Team Group"},
+// { 4, 0x70, "Sinett"},
+ { 4, 0xf1, "Toshiba"},
+// { 4, 0xf2, "Tensilica"},
+// { 4, 0x73, "SiRF Technology"},
+// { 4, 0xf4, "Bacoc"},
+// { 4, 0x75, "SMaL Camera Technologies"},
+ { 4, 0x76, "Thomson SC"},
+// { 4, 0xf7, "Airgo Networks"},
+// { 4, 0xf8, "Wisair"},
+// { 4, 0x79, "SigmaTel"},
+// { 4, 0x7a, "Arkados"},
+// { 4, 0xfb, "Compete IT KG"},
+// { 4, 0x7c, "Eudar Technology"},
+// { 4, 0xfd, "Focus Enhancements"},
+// { 4, 0xfe, "Xyratex"},
+// { 5, 0x01, "Specular Networks"},
+ { 5, 0x02, "Patriot Memory"},
+// { 5, 0x83, "U-Chip Technology Corp."},
+// { 5, 0x04, "Silicon Optix"},
+// { 5, 0x85, "Greenfield Networks"},
+ { 5, 0x86, "CompuRAM"},
+// { 5, 0x07, "Stargen"},
+// { 5, 0x08, "NetCell"},
+// { 5, 0x89, "Excalibrus Technologies"},
+// { 5, 0x8a, "SCM Microsystems"},
+// { 5, 0x0b, "Xsigo Systems"},
+// { 5, 0x8c, "CHIPS & Systems"},
+// { 5, 0x0d, "Tier"},
+// { 5, 0x0e, "CWRL Labs"},
+// { 5, 0x8f, "Teradici"},
+// { 5, 0x10, "Gigaram"},
+// { 5, 0x91, "g2 Microsystems"},
+// { 5, 0x92, "PowerFlash Semiconductor"},
+// { 5, 0x13, "P.A. Semi"},
+ { 5, 0x94, "NovaTech"},
+// { 5, 0x15, "c2 Microsystems"},
+// { 5, 0x16, "Level5 Networks"},
+ { 5, 0x97, "COS Memory"},
+// { 5, 0x98, "Innovasic Semiconductor"},
+// { 5, 0x19, "02IC"},
+// { 5, 0x1a, "Tabula"},
+ { 5, 0x9b, "Crucial"},
+// { 5, 0x1c, "Chelsio Communications"},
+// { 5, 0x9d, "Solarflare Communications"},
+// { 5, 0x9e, "Xambala"},
+// { 5, 0x1f, "EADS Astrium"},
+// { 5, 0x20, "Terra Semiconductor"},
+// { 5, 0xa1, "Imaging Works"},
+// { 5, 0xa2, "Astute Networks"},
+// { 5, 0x23, "Tzero"},
+// { 5, 0xa4, "Emulex"},
+// { 5, 0x25, "Power-One"},
+// { 5, 0x26, "Pulse~LINK"},
+// { 5, 0xa7, "Hon Hai Precision Industry"},
+// { 5, 0xa8, "White Rock Networks"},
+// { 5, 0x29, "Telegent Systems USA"},
+// { 5, 0x2a, "Atrua Technologies"},
+// { 5, 0xab, "Acbel Polytech"},
+// { 5, 0x2c, "eRide"},
+ { 5, 0xad, "ULi"},
+// { 5, 0xae, "Magnum Semiconductor"},
+// { 5, 0x2f, "neoOne Technology"},
+// { 5, 0xb0, "Connex Technology"},
+// { 5, 0x31, "Stream Processors"},
+// { 5, 0x32, "Focus Enhancements"},
+// { 5, 0xb3, "Telecis Wireless"},
+// { 5, 0x34, "uNav Microelectronics"},
+// { 5, 0xb5, "Tarari"},
+// { 5, 0xb6, "Ambric"},
+// { 5, 0x37, "Newport Media"},
+// { 5, 0x38, "VMTS"},
+// { 5, 0xb9, "Enuclia Semiconductor"},
+// { 5, 0xba, "Virtium Technology"},
+// { 5, 0x3b, "Solid State System"},
+// { 5, 0xbc, "Kian Tech LLC"},
+// { 5, 0x3d, "Artimi"},
+ { 5, 0x3e, "PQI"},
+// { 5, 0xbf, "Avago Technologies"},
+// { 5, 0x40, "ADTechnology"},
+ { 5, 0xc1, "Sigma Designs"},
+// { 5, 0xc2, "SiCortex"},
+// { 5, 0x43, "Ventura Technology Group"},
+// { 5, 0xc4, "eASIC"},
+// { 5, 0x45, "M.H.S. SAS"},
+ { 5, 0x46, "MSI"},
+// { 5, 0xc7, "Rapport"},
+// { 5, 0xc8, "Makway International"},
+// { 5, 0x49, "Broad Reach Engineering"},
+// { 5, 0x4a, "Semiconductor Mfg Intl Corp"},
+// { 5, 0xcb, "SiConnect"},
+// { 5, 0x4c, "FCI USA"},
+// { 5, 0xcd, "Validity Sensors"},
+// { 5, 0xce, "Coney Technology"},
+// { 5, 0x4f, "Spans Logic"},
+// { 5, 0xd0, "Neterion"},
+ { 5, 0x51, "Qimonda"},
+// { 5, 0x52, "New Japan Radio"},
+// { 5, 0xd3, "Velogix"},
+// { 5, 0x54, "Montalvo Systems"},
+// { 5, 0xd5, "iVivity"},
+ { 5, 0xd6, "Walton Chaintech"},
+ { 5, 0x57, "AENEON"},
+// { 5, 0x58, "Lorom Industrial"},
+// { 5, 0xd9, "Radiospire Networks"},
+// { 5, 0xda, "Sensio Technologies"},
+// { 5, 0x5b, "Nethra Imaging"},
+ { 5, 0xdc, "Hexon"},
+// { 5, 0x5d, "CompuStocx (CSX)"},
+// { 5, 0x5e, "Methode Electronics"},
+// { 5, 0xdf, "Connect One"},
+// { 5, 0xe0, "Opulan Technologies"},
+// { 5, 0x61, "Septentrio NV"},
+ { 5, 0x62, "Goldenmars"},
+ { 5, 0xe3, "Kreton"},
+// { 5, 0x64, "Cochlear"},
+// { 5, 0xe5, "Altair Semiconductor"},
+// { 5, 0xe6, "NetEffect"},
+// { 5, 0x67, "Spansion"},
+// { 5, 0x68, "Taiwan Semiconductor Mfg"},
+// { 5, 0xe9, "Emphany Systems"},
+// { 5, 0xea, "ApaceWave Technologies"},
+// { 5, 0x6b, "Mobilygen"},
+// { 5, 0xec, "Tego"},
+// { 5, 0x6d, "Cswitch"},
+// { 5, 0x6e, "Haier (Beijing) IC Design"},
+// { 5, 0xef, "MetaRAM"},
+// { 5, 0x70, "Axel Electronics"},
+// { 5, 0xf1, "Tilera"},
+// { 5, 0xf2, "Aquantia"},
+// { 5, 0x73, "Vivace Semiconductor"},
+// { 5, 0xf4, "Redpine Signals"},
+// { 5, 0x75, "Octalica"},
+// { 5, 0x76, "InterDigital Communications"},
+ { 5, 0xf7, "Avant Technology"},
+ { 5, 0xf8, "Asrock"},
+// { 5, 0x79, "Availink"},
+// { 5, 0x7a, "Quartics"},
+// { 5, 0xfb, "Element CXI"},
+// { 5, 0x7c, "Innovaciones Microelectronicas"},
+// { 5, 0xfd, "VeriSilicon Microelectronics"},
+// { 5, 0xfe, "W5 Networks"},
+// { 6, 0x01, "MOVEKING"},
+// { 6, 0x02, "Mavrix Technology"},
+// { 6, 0x83, "CellGuide"},
+// { 6, 0x04, "Faraday Technology"},
+// { 6, 0x85, "Diablo Technologies"},
+// { 6, 0x86, "Jennic"},
+// { 6, 0x07, "Octasic"},
+ { 6, 0x08, "Molex"},
+// { 6, 0x89, "3Leaf Networks"},
+// { 6, 0x8a, "Bright Micron Technology"},
+// { 6, 0x0b, "Netxen"},
+// { 6, 0x8c, "NextWave Broadband"},
+// { 6, 0x0d, "DisplayLink"},
+// { 6, 0x0e, "ZMOS Technology"},
+// { 6, 0x8f, "Tec-Hill"},
+// { 6, 0x10, "Multigig"},
+// { 6, 0x91, "Amimon"},
+// { 6, 0x92, "Euphonic Technologies"},
+// { 6, 0x13, "BRN Phoenix"},
+// { 6, 0x94, "InSilica"},
+// { 6, 0x15, "Ember"},
+ { 6, 0x16, "Avexir"},
+// { 6, 0x97, "Echelon"},
+// { 6, 0x98, "Edgewater Computer Systems"},
+// { 6, 0x19, "XMOS Semiconductor"},
+// { 6, 0x1a, "GENUSION"},
+ { 6, 0x9b, "Memory Corp NV"},
+// { 6, 0x1c, "SiliconBlue Technologies"},
+// { 6, 0x9d, "Rambus"},
+// { 6, 0x9e, "Andes Technology"},
+// { 6, 0x1f, "Coronis Systems"},
+// { 6, 0x20, "Achronix Semiconductor"},
+// { 6, 0xa1, "Siano Mobile Silicon"},
+// { 6, 0xa2, "Semtech"},
+// { 6, 0x23, "Pixelworks"},
+// { 6, 0xa4, "Gaisler Research AB"},
+// { 6, 0x25, "Teranetics"},
+// { 6, 0x26, "Toppan Printing"},
+// { 6, 0xa7, "Kingxcon"},
+ { 6, 0xa8, "SiS"},
+// { 6, 0x29, "I-O Data Device"},
+// { 6, 0x2a, "NDS Americas"},
+// { 6, 0xab, "Solomon Systech Limited"},
+// { 6, 0x2c, "On Demand Microelectronics"},
+// { 6, 0xad, "Amicus Wireless"},
+// { 6, 0xae, "SMARDTV SNC"},
+// { 6, 0x2f, "Comsys Communication"},
+// { 6, 0xb0, "Movidia"},
+// { 6, 0x31, "Javad GNSS"},
+// { 6, 0x32, "Montage Technology Group"},
+ { 6, 0xb3, "Trident"},
+ { 6, 0x34, "Super Talent"},
+// { 6, 0xb5, "Optichron"},
+// { 6, 0xb6, "Future Waves UK"},
+// { 6, 0x37, "SiBEAM"},
+// { 6, 0x38, "Inicore,"},
+// { 6, 0xb9, "Virident Systems"},
+// { 6, 0xba, "M2000"},
+// { 6, 0x3b, "ZeroG Wireless"},
+ { 6, 0xbc, "Gingle"},
+// { 6, 0x3d, "Space Micro"},
+// { 6, 0x3e, "Wilocity"},
+// { 6, 0xbf, "Novafora, Ic."},
+// { 6, 0x40, "iKoa"},
+ { 6, 0xc1, "ASint"},
+ { 6, 0xc2, "Ramtron"},
+// { 6, 0x43, "Plato Networks"},
+// { 6, 0xc4, "IPtronics AS"},
+// { 6, 0x45, "Infinite-Memories"},
+// { 6, 0x46, "Parade Technologies"},
+// { 6, 0xc7, "Dune Networks"},
+// { 6, 0xc8, "GigaDevice Semiconductor"},
+// { 6, 0x49, "Modu"},
+// { 6, 0x4a, "CEITEC"},
+// { 6, 0xcb, "Northrop Grumman"},
+// { 6, 0x4c, "XRONET"},
+// { 6, 0xcd, "Sicon Semiconductor AB"},
+// { 6, 0xce, "Atla Electronics"},
+ { 6, 0x4f, "TOPRAM"},
+// { 6, 0xd0, "Silego Technology"},
+ { 6, 0x51, "Kinglife"},
+// { 6, 0x52, "Ability Industries"},
+// { 6, 0xd3, "Silicon Power Computer & Communications"},
+// { 6, 0x54, "Augusta Technology"},
+// { 6, 0xd5, "Nantronics Semiconductors"},
+// { 6, 0xd6, "Hilscher Gesellschaft"},
+// { 6, 0x57, "Quixant"},
+// { 6, 0x58, "Percello"},
+// { 6, 0xd9, "NextIO"},
+// { 6, 0xda, "Scanimetrics"},
+// { 6, 0x5b, "FS-Semi Company"},
+// { 6, 0xdc, "Infinera"},
+ { 6, 0x5d, "SandForce"},
+ { 6, 0x5e, "Lexar Media"},
+// { 6, 0xdf, "Teradyne"},
+ { 6, 0xe0, "Memory Exchange Corp."},
+// { 6, 0x61, "Suzhou Smartek Electronics"},
+ { 6, 0x62, "Avantium"},
+// { 6, 0xe3, "ATP Electronics"},
+// { 6, 0x64, "Valens Semiconductor"},
+// { 6, 0xe5, "Agate Logic"},
+// { 6, 0xe6, "Netronome"},
+// { 6, 0x67, "Zenverge"},
+// { 6, 0x68, "N-trig"},
+// { 6, 0xe9, "SanMax Technologies"},
+// { 6, 0xea, "Contour Semiconductor"},
+ { 6, 0x6b, "TwinMOS"},
+ { 6, 0xec, "Silicon Systems"},
+// { 6, 0x6d, "V-Color Technology"},
+// { 6, 0x6e, "Certicom"},
+// { 6, 0xef, "JSC ICC Milandr"},
+// { 6, 0x70, "PhotoFast Global"},
+ { 6, 0xf1, "InnoDisk"},
+ { 6, 0xf2, "Muscle Power"},
+// { 6, 0x73, "Energy Micro"},
+// { 6, 0xf4, "Innofidei"},
+// { 6, 0x75, "CopperGate Communications"},
+// { 6, 0x76, "Holtek Semiconductor"},
+// { 6, 0xf7, "Myson Century"},
+// { 6, 0xf8, "FIDELIX"},
+// { 6, 0x79, "Red Digital Cinema"},
+// { 6, 0x7a, "Densbits Technology"},
+// { 6, 0xfb, "Zempro"},
+// { 6, 0x7c, "MoSys"},
+// { 6, 0xfd, "Provigent"},
+// { 6, 0xfe, "Triad Semiconductor"},
+// { 8, 0x01, "Siklu Communication"},
+// { 8, 0x02, "A Force Manufacturing"},
+ { 8, 0x83, "Strontium"},
+// { 8, 0x04, "Abilis Systems"},
+// { 8, 0x85, "Siglead"},
+// { 8, 0x86, "Ubicom"},
+// { 8, 0x07, "Unifosa"},
+// { 8, 0x08, "Stretch"},
+// { 8, 0x89, "Lantiq Deutschland"},
+// { 8, 0x8a, "Visipro."},
+ { 8, 0x0b, "EKMemory"},
+// { 8, 0x8c, "Microelectronics Institute ZTE"},
+// { 8, 0x0d, "Cognovo"},
+// { 8, 0x0e, "Carry Technology"},
+ { 8, 0x8f, "Nokia"},
+ { 8, 0x10, "King Tiger"},
+// { 8, 0x91, "Sierra Wireless"},
+ { 8, 0x92, "HT Micron"},
+ { 8, 0x13, "Albatron"},
+// { 8, 0x94, "Leica Geosystems AG"},
+// { 8, 0x15, "BroadLight"},
+// { 8, 0x16, "AEXEA"},
+// { 8, 0x97, "ClariPhy Communications"},
+// { 8, 0x98, "Green Plug"},
+// { 8, 0x19, "Design Art Networks"},
+// { 8, 0x1a, "Mach Xtreme Technology"},
+// { 8, 0x9b, "ATO Solutions"},
+// { 8, 0x1c, "Ramsta"},
+// { 8, 0x9d, "Greenliant Systems"},
+// { 8, 0x9e, "Teikon"},
+// { 8, 0x1f, "Antec Hadron"},
+// { 8, 0x20, "NavCom Technology"},
+// { 8, 0xa1, "Shanghai Fudan Microelectronics"},
+// { 8, 0xa2, "Calxeda"},
+// { 8, 0x23, "JSC EDC Electronics"},
+// { 8, 0xa4, "Kandit Technology"},
+// { 8, 0x25, "Ramos Technology"},
+// { 8, 0x26, "Goldenmars Technology"},
+// { 8, 0xa7, "XeL Technology"},
+// { 8, 0xa8, "Newzone"},
+ { 8, 0x29, "MercyPower"},
+// { 8, 0x2a, "Nanjing Yihuo Technology."},
+// { 8, 0xab, "Nethra Imaging"},
+// { 8, 0x2c, "SiTel Semiconductor BV"},
+// { 8, 0xad, "SolidGear"},
+ { 8, 0xae, "Topower"},
+// { 8, 0x2f, "Wilocity"},
+// { 8, 0xb0, "Profichip"},
+// { 8, 0x31, "Gerad Technologies"},
+ { 8, 0x32, "Ritek"},
+// { 8, 0xb3, "Gomos Technology Limited"},
+ { 8, 0x34, "Memoright"},
+// { 8, 0xb5, "D-Broad"},
+// { 8, 0xb6, "HiSilicon Technologies"},
+// { 8, 0x37, "Syndiant ."},
+// { 8, 0x38, "Enverv"},
+// { 8, 0xb9, "Cognex"},
+// { 8, 0xba, "Xinnova Technology"},
+ { 8, 0x3b, "Ultron"},
+// { 8, 0xbc, "Concord Idea"},
+// { 8, 0x3d, "AIM"},
+// { 8, 0x3e, "Lifetime Memory Products"},
+// { 8, 0xbf, "Ramsway"},
+// { 8, 0x40, "Recore Systems B.V."},
+// { 8, 0xc1, "Haotian Jinshibo Science Tech"},
+// { 8, 0xc2, "Being Advanced Memory"},
+// { 8, 0x43, "Adesto Technologies"},
+// { 8, 0xc4, "Giantec Semiconductor"},
+// { 8, 0x45, "HMD Electronics AG"},
+// { 8, 0x46, "Gloway International (HK)"},
+// { 8, 0xc7, "Kingcore"},
+// { 8, 0xc8, "Anucell Technology Holding"},
+// { 8, 0x49, "Accord Software & Systems Pvt."},
+// { 8, 0x4a, "Active-Semi"},
+// { 8, 0xcb, "Denso"},
+// { 8, 0x4c, "TLSI"},
+// { 8, 0xcd, "Shenzhen Daling Electronic"},
+// { 8, 0xce, "Mustang"},
+// { 8, 0x4f, "Orca Systems"},
+// { 8, 0xd0, "Passif Semiconductor"},
+// { 8, 0x51, "GigaDevice Semiconductor (Beijing)"},
+// { 8, 0x52, "Memphis Electronic"},
+// { 8, 0xd3, "Beckhoff Automation"},
+// { 8, 0x54, "Harmony Semiconductor Corp"},
+// { 8, 0xd5, "Air Computers SRL"},
+ { 8, 0xd6, "TMT Memory"},
+ { 9, 0xff, ""}
};
@@ -1,30 +1,25 @@ -/* lib.c - MemTest-86 Version 3.0 +/* lib.c - MemTest-86 Version 3.4 * * Released under version 2 of the Gnu Public License. - * By Chris Brady, cbrady@sgi.com - * ---------------------------------------------------- - * MemTest86+ V4.00 Specific code (GPL V2.0) - * By Samuel DEMEULEMEESTER, memtest@memtest.org - * http://www.canardplus.com - http://www.memtest.org -*/ - + * By Chris Brady + */ #include "io.h" #include "serial.h" #include "test.h" #include "config.h" #include "screen_buffer.h" +#include "stdint.h" +#include "cpuid.h" #include "smp.h" -#define NULL 0 int slock = 0, lsr = 0; short serial_cons = SERIAL_CONSOLE_DEFAULT; - #if SERIAL_TTY != 0 && SERIAL_TTY != 1 #error Bad SERIAL_TTY. Only ttyS0 and ttyS1 are supported. #endif short serial_tty = SERIAL_TTY; -const short serial_base_ports[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; +const short serial_base_ports[] = {0x3f8, 0x2f8}; #if ((115200%SERIAL_BAUD_RATE) != 0) #error Bad default baud rate @@ -33,53 +28,55 @@ int serial_baud_rate = SERIAL_BAUD_RATE; unsigned char serial_parity = 0; unsigned char serial_bits = 8; -char buf[18]; - struct ascii_map_str { - int ascii; - int keycode; + int ascii; + int keycode; }; -char *codes[] = { - " Divide", - " Debug", - " NMI", - " Brkpnt", - "Overflow", - " Bound", - " Inv_Op", - " No_Math", - "Double_Fault", - "Seg_Over", - " Inv_TSS", - " Seg_NP", - "Stack_Fault", - "Gen_Prot", - "Page_Fault", - " Resvd", - " FPE", - "Alignment", - " Mch_Chk", - "SIMD FPE" -}; +inline void reboot(void) +{ + + /* tell the BIOS to do a cold start */ + *((unsigned short *)0x472) = 0x0; + + while(1) + { + outb(0xFE, 0x64); + outb(0x02, 0xcf9); /* reset that doesn't rely on the keyboard controller */ + outb(0x04, 0xcf9); + outb(0x0E, 0xcf9); + } +} -struct eregs { - ulong ss; - ulong ds; - ulong esp; - ulong ebp; - ulong esi; - ulong edi; - ulong edx; - ulong ecx; - ulong ebx; - ulong eax; - ulong vect; - ulong code; - ulong eip; - ulong cs; - ulong eflag; -}; +int strlen(char * string){ + int i=0; + while(*string++){i++;}; + return i; +} + +int strstr(char *haystack, char * needle) +{ + int i=0,j=0; + int here=0; + while(1){ + if(needle[i]==haystack[j]) + { + if(here==0) + here=j; + i++;j++; + if(i>=strlen(needle)) + { + return here; + } + if(j>=strlen(haystack)) + { + return -1; + } + } else { + j++;i=0;here=0; + } + } +} int memcmp(const void *s1, const void *s2, ulong count) { @@ -93,19 +90,6 @@ int memcmp(const void *s1, const void *s2, ulong count) return 0; } -void memcpy (void *dst, void *src, int len) -{ - char *s = (char*)src; - char *d = (char*)dst; - int i; - - if (len <= 0) { - return; - } - for (i = 0 ; i < len; i++) { - *d++ = *s++; - } -} int strncmp(const char *s1, const char *s2, ulong n) { signed char res = 0; while (n) { @@ -183,12 +167,11 @@ unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) { return result; } - /* * Scroll the error message area of the screen as needed * Starts at line LINE_SCROLL and ends at line 23 */ -void scroll(void) +void scroll(void) { int i, j; char *s, tmp; @@ -201,23 +184,23 @@ void scroll(void) while (slock) { check_input(); } - for (i=LINE_SCROLL; i<23; i++) { + for (i=LINE_SCROLL; i<23; i++) { s = (char *)(SCREEN_ADR + ((i+1) * 160)); for (j=0; j<160; j+=2, s+=2) { *(s-160) = *s; - tmp = get_scrn_buf(i+1, j/2); - set_scrn_buf(i, j/2, tmp); + tmp = get_scrn_buf(i+1, j/2); + set_scrn_buf(i, j/2, tmp); } } /* Clear the newly opened line */ s = (char *)(SCREEN_ADR + (23 * 160)); for (j=0; j<80; j++) { *s = ' '; - set_scrn_buf(23, j, ' '); + set_scrn_buf(23, j, ' '); s += 2; } - tty_print_region(LINE_SCROLL, 0, 23, 79); - } + tty_print_region(LINE_SCROLL, 0, 23, 79); + } } /* @@ -236,6 +219,17 @@ void clear_scroll(void) } /* + * Place a single character on screen + */ +void cplace(int y, int x, const char c) +{ + char *dptr; + + dptr = (char *)(SCREEN_ADR + (160*y) + (2*x)); + *dptr = c; +} + +/* * Print characters on screen */ void cprint(int y, int x, const char *text) @@ -247,37 +241,50 @@ void cprint(int y, int x, const char *text) for (i=0; text[i]; i++) { *dptr = text[i]; dptr += 2; - } - tty_print_line(y, x, text); + } + tty_print_line(y, x, text); } -void itoa(char s[], int n) +void itoa(char s[], int n) { - int i, sign; - - if((sign = n) < 0) - n = -n; - i=0; - do { - s[i++] = n % 10 + '0'; - } while ((n /= 10) > 0); - if(sign < 0) - s[i++] = '-'; - s[i] = '\0'; - reverse(s); + int i, sign; + + if((sign = n) < 0) + n = -n; + i=0; + do { + s[i++] = n % 10 + '0'; + } while ((n /= 10) > 0); + if(sign < 0) + s[i++] = '-'; + s[i] = '\0'; + reverse(s); } void reverse(char s[]) { - int c, i, j; - for(j = 0; s[j] != 0; j++) - ; - - for(i=0, j = j - 1; i < j; i++, j--) { - c = s[i]; - s[i] = s[j]; - s[j] = c; + int c, i, j; + for(j = 0; s[j] != 0; j++) + ; + + for(i=0, j = j - 1; i < j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} +void memcpy (void *dst, void *src, int len) +{ + char *s = (char*)src; + char *d = (char*)dst; + int i; + + if (len <= 0) { + return; } + for (i = 0 ; i < len; i++) { + *d++ = *s++; + } } /* @@ -311,6 +318,7 @@ void dprint(int y, int x, ulong val, int len, int right) { ulong j, k; int i, flag=0; + char buf[18]; if (val > 999999999 || len > 9) { return; @@ -343,16 +351,16 @@ void dprint(int y, int x, ulong val, int len, int right) continue; } if (k == 0 && flag == 0) { - continue; + continue; } buf[i++] = k + '0'; val -= k * j; } else { - if (flag == 0 && i < len-1) { - buf[i++] = '0'; - } else { - buf[i++] = ' '; - } + if (flag == 0 && i < len-1) { + buf[i++] = '0'; + } else { + buf[i++] = ' '; + } } flag++; } @@ -361,56 +369,38 @@ void dprint(int y, int x, ulong val, int len, int right) cprint(y,x,buf); } - -/* - * Get_number of digits - */ -int getnum(ulong val) -{ - int len = 0; - int i = 1; - - while(i <= val) - { - len++; - i *= 10; - } - - return len; - -} - /* * Print a hex number on screen at least digits long */ void hprint2(int y,int x, unsigned long val, int digits) { - unsigned long j; - int i, idx, flag = 0; + unsigned long j; + int i, idx, flag = 0; + char buf[18]; for (i=0, idx=0; i<8; i++) { j = val >> (28 - (4 * i)); - j &= 0xf; - if (j < 10) { - if (flag || j || i == 7) { - buf[idx++] = j + '0'; - flag++; - } else { - buf[idx++] = '0'; - } - } else { - buf[idx++] = j + 'a' - 10; - flag++; - } - } - if (digits > 8) { - digits = 8; - } - if (flag > digits) { - digits = flag; + j &= 0xf; + if (j < 10) { + if (flag || j || i == 7) { + buf[idx++] = j + '0'; + flag++; + } else { + buf[idx++] = '0'; + } + } else { + buf[idx++] = j + 'a' - 10; + flag++; + } } + if (digits > 8) { + digits = 8; + } + if (flag > digits) { + digits = flag; + } buf[idx] = 0; - cprint(y,x,buf + (idx - digits)); + cprint(y,x,buf + (idx - digits)); } /* @@ -420,7 +410,7 @@ void hprint3(int y,int x, unsigned long val, int digits) { unsigned long j; int i, idx, flag = 0; - + char buf[18]; for (i=0, idx=0; i<digits; i++) { j = 0xf & val; @@ -455,7 +445,7 @@ void hprint(int y, int x, unsigned long val) */ void xprint(int y,int x, ulong val) { - ulong j; + ulong j; j = (val & 0xffc00000) >> 20; dprint(y, x, j, 4, 0); @@ -467,12 +457,54 @@ void xprint(int y,int x, ulong val) dprint(y, x+10, j, 4, 0); } +char *codes[] = { + " Divide", + " Debug", + " NMI", + " Brkpnt", + "Overflow", + " Bound", + " Inv_Op", + " No_Math", + "Double_Fault", + "Seg_Over", + " Inv_TSS", + " Seg_NP", + "Stack_Fault", + "Gen_Prot", + "Page_Fault", + " Resvd", + " FPE", + "Alignment", + " Mch_Chk", + "SIMD FPE" +}; + +struct eregs { + ulong ss; + ulong ds; + ulong esp; + ulong ebp; + ulong esi; + ulong edi; + ulong edx; + ulong ecx; + ulong ebx; + ulong eax; + ulong vect; + ulong code; + ulong eip; + ulong cs; + ulong eflag; +}; + /* Handle an interrupt */ void inter(struct eregs *trap_regs) { int i, line; unsigned char *pp; ulong address = 0; + int my_cpu_num = smp_my_cpu_num(); /* Get the page fault address */ if (trap_regs->vect == 14) { @@ -488,13 +520,14 @@ void inter(struct eregs *trap_regs) #endif /* clear scrolling region */ - pp=(unsigned char *)(SCREEN_ADR+(2*80*(LINE_SCROLL-2))); - for(i=0; i<2*80*(24-LINE_SCROLL-2); i++, pp+=2) { - *pp = ' '; - } + pp=(unsigned char *)(SCREEN_ADR+(2*80*(LINE_SCROLL-2))); + for(i=0; i<2*80*(24-LINE_SCROLL-2); i++, pp+=2) { + *pp = ' '; + } line = LINE_SCROLL-2; - cprint(line, 0, "Unexpected Interrupt - Halting"); + cprint(line, 0, "Unexpected Interrupt - Halting CPU"); + dprint(line, COL_MID + 4, my_cpu_num, 2, 1); cprint(line+2, 0, " Type: "); if (trap_regs->vect <= 19) { cprint(line+2, 7, codes[trap_regs->vect]); @@ -509,6 +542,10 @@ void inter(struct eregs *trap_regs) hprint(line+5, 7, trap_regs->eflag); cprint(line+6, 0, " Code: "); hprint(line+6, 7, trap_regs->code); + cprint(line+7, 0, " DS: "); + hprint(line+7, 7, trap_regs->ds); + cprint(line+8, 0, " SS: "); + hprint(line+8, 7, trap_regs->ss); if (trap_regs->vect == 14) { /* Page fault address */ cprint(line+7, 0, " Addr: "); @@ -531,21 +568,18 @@ void inter(struct eregs *trap_regs) hprint(line+8, 25, trap_regs->ebp); cprint(line+9, 20, "esp: "); hprint(line+9, 25, trap_regs->esp); - cprint(line+7, 0, " DS: "); - hprint(line+7, 7, trap_regs->ds); - cprint(line+8, 0, " SS: "); - hprint(line+8, 7, trap_regs->ss); + cprint(line+1, 38, "Stack:"); - for (i=0; i<12; i++) { + for (i=0; i<10; i++) { hprint(line+2+i, 38, trap_regs->esp+(4*i)); hprint(line+2+i, 47, *(ulong*)(trap_regs->esp+(4*i))); - hprint(line+2+i, 57, trap_regs->esp+(4*(i+12))); - hprint(line+2+i, 66, *(ulong*)(trap_regs->esp+(4*(i+12)))); + hprint(line+2+i, 57, trap_regs->esp+(4*(i+10))); + hprint(line+2+i, 66, *(ulong*)(trap_regs->esp+(4*(i+10)))); } cprint(line+11, 0, "CS:EIP: "); pp = (unsigned char *)trap_regs->eip; - for(i = 0; i < 10; i++) { + for(i = 0; i < 9; i++) { hprint2(line+11, 8+(3*i), pp[i], 2); } @@ -554,22 +588,14 @@ void inter(struct eregs *trap_regs) } } -void set_cache(int val) +void set_cache(int val) { - extern struct cpu_ident cpu_id; - /* 386's don't have a cache */ - if ((cpu_id.cpuid < 1) && (cpu_id.type == 3)) { - cprint(LINE_INFO, COL_CACHE, "none"); - return; - } switch(val) { case 0: - cache_off(); - cprint(LINE_INFO, COL_CACHE, "off"); + cache_off(); break; case 1: cache_on(); - cprint(LINE_INFO, COL_CACHE, " on"); break; } } @@ -603,13 +629,10 @@ void check_input(void) if ((c = get_key())) { switch(c & 0x7f) { - case 1: + case 1: /* "ESC" key was pressed, bail out. */ cprint(LINE_RANGE, COL_MID+23, "Halting... "); - - /* tell the BIOS to do a warm start */ - *((unsigned short *)0x472) = 0x1234; - outb(0xfe,0x64); + reboot(); break; case 46: /* c - Configure */ @@ -635,9 +658,9 @@ void check_input(void) void footer() { - cprint(24, 0, "(ESC)Reboot (c)configuration (SP)scroll_lock (CR)scroll_unlock"); + cprint(24, 0, "(ESC)exit (c)configuration (SP)scroll_lock (CR)scroll_unlock"); if (slock) { - cprint(24, 74, "LOCKED"); + cprint(24, 74, "Locked"); } else { cprint(24, 74, " "); } @@ -657,7 +680,7 @@ ulong getval(int x, int y, int result_shift) buf[i] = ' '; } buf[sizeof(buf)/sizeof(buf[0]) -1] = '\0'; - + wait_keyup(); done = 0; n = 0; @@ -711,7 +734,7 @@ ulong getval(int x, int y, int result_shift) } /* Don't allow anything to be entered after a suffix */ if (n > 0 && ( - (buf[n-1] == 'p') || (buf[n-1] == 'g') || + (buf[n-1] == 'p') || (buf[n-1] == 'g') || (buf[n-1] == 'm') || (buf[n-1] == 'k'))) { buf[n] = ' '; } @@ -743,7 +766,7 @@ ulong getval(int x, int y, int result_shift) shift -= result_shift; /* Compute our current value */ - val = simple_strtoul(buf, NULL, base); + val = simple_strtoul(buf, 0, base); if (shift > 0) { if (shift >= 32) { val = 0xffffffff; @@ -765,7 +788,7 @@ void ttyprint(int y, int x, const char *p) { static char sx[3]; static char sy[3]; - + sx[0]='\0'; sy[0]='\0'; x++; y++; @@ -779,11 +802,10 @@ void ttyprint(int y, int x, const char *p) serial_echo_print(p); } - void serial_echo_init(void) { int comstat, hi, lo, serial_div; - unsigned char lcr; + unsigned char lcr; /* read the Divisor Latch */ comstat = serial_echo_inb(UART_LCR); @@ -801,18 +823,36 @@ void serial_echo_init(void) serial_echo_outb((serial_div >> 8) & 0xff, UART_DLM); serial_echo_outb(lcr, UART_LCR); /* Done with divisor */ - /* Prior to disabling interrupts, read the LSR and RBR * registers */ comstat = serial_echo_inb(UART_LSR); /* COM? LSR */ comstat = serial_echo_inb(UART_RX); /* COM? RBR */ serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */ - clear_screen_buf(); + clear_screen_buf(); return; } +/* + * Get_number of digits + */ +int getnum(ulong val) +{ + int len = 0; + int i = 1; + + while(i <= val) + { + len++; + i *= 10; + } + + return len; + +} + + void serial_echo_print(const char *p) { if (!serial_cons) { @@ -841,9 +881,9 @@ void serial_echo_print(const char *p) */ struct ascii_map_str ser_map[] = /*ascii keycode ascii keycode*/ -{ +{ /* Special cases come first so I can leave - * their "normal" mapping in the table, + * their ``normal'' mapping in the table, * without it being activated. */ { 27, 0x01}, /* ^[/ESC -> ESC */ @@ -1026,7 +1066,6 @@ void wait_keyup( void ) { } } - /* * Handles "console=<param>" command line option * @@ -1053,8 +1092,8 @@ void serial_console_setup(char *param) if (option == param) return; /* there were no digits */ - if (tty > 3) - return; /* only ttyS0 to ttyS3 supported */ + if (tty > 1) + return; /* only ttyS0 and ttyS1 supported */ if (*option == '\0' || *option == ' ') goto save_tty; /* no options given, just ttyS? */ @@ -1102,76 +1141,59 @@ void serial_console_setup(char *param) end++; - if (*end != '\0' && *end != ' ') + if (*end != '\0' || *end != ' ') return; /* garbage at the end */ serial_bits = bits; - save_parity: + save_parity: serial_parity = parity; - save_baud_rate: + save_baud_rate: serial_baud_rate = (int) baud_rate; - save_tty: + save_tty: serial_tty = (short) tty; serial_cons = 1; } - -#ifdef LP -#define DATA 0x00 -#define STATUS 0x01 -#define CONTROL 0x02 - -#define LP_PBUSY 0x80 /* inverted input, active high */ -#define LP_PERRORP 0x08 /* unchanged input, active low */ - -#define LP_PSELECP 0x08 /* inverted output, active low */ -#define LP_PINITP 0x04 /* unchanged output, active low */ -#define LP_PSTROBE 0x01 /* short high output on raising edge */ - -#define DELAY 0x10c6ul - -void lp_wait(ulong xloops) -{ - int d0; - __asm__("mull %0" - :"=d" (xloops), "=&a" (d0) - :"1" (xloops),"0" (current_cpu_data.loops_per_sec)); - __delay(xloops); -} -static void __delay(ulong loops) +/* Get a comma seperated list of numbers */ +void get_list(int x, int y, int len, char *buf) { - int d0; - __asm__ __volatile__( - "\tjmp 1f\n" - ".align 16\n" - "1:\tjmp 2f\n" - ".align 16\n" - "2:\tdecl %0\n\tjns 2b" - :"=&a" (d0) - :"0" (loops)); -} + int c, n = 0; -put_lp(char c, short port) -{ - unsigned char status; - - /* Wait for printer to be ready */ - while (1) { - status = inb(STATUS(port)); - if (status & LP_PERRORP) { - if (status & LP_PBUSY) { - break; + len--; + wait_keyup(); + while(1) { + /* Read a new character and process it */ + c = get_key(); + switch(c) { + case 0x1c: /* CR */ + /* If something has been entered we are done */ + if(n) { + buf[n] = 0; + return; + } + break; + case 0x0e: /* BS */ + if (n > 0) { + n -= 1; + buf[n] = ' '; } + break; + case 0x0B: buf[n++] = '0'; break; + case 0x02: buf[n++] = '1'; break; + case 0x03: buf[n++] = '2'; break; + case 0x04: buf[n++] = '3'; break; + case 0x05: buf[n++] = '4'; break; + case 0x06: buf[n++] = '5'; break; + case 0x07: buf[n++] = '6'; break; + case 0x08: buf[n++] = '7'; break; + case 0x09: buf[n++] = '8'; break; + case 0x0a: buf[n++] = '9'; break; + case 0x33: buf[n++] = ','; break; + } + cprint(x, y, buf); + if (n >= len) { + buf[n] = 0; + return; } } - - outb(d, DATA(c)); - lp_wait(DELAY); - outb((LP_PSELECP | LP_PINITP | LP_PSTROBE), CONTROL(port)); - lp_wait(DELAY); - outb((LP_PSELECP | LP_PINITP), CONTROL(port)); - lp_wait(DELAY); -} - -#endif - +}
\ No newline at end of file @@ -1,141 +1,269 @@ -/* main.c - MemTest-86 Version 3.2 +/* + * MemTest86+ V5 Specific code (GPL V2.0) + * By Samuel DEMEULEMEESTER, sdemeule@memtest.org + * http://www.canardpc.com - http://www.memtest.org + * ------------------------------------------------ + * main.c - MemTest-86 Version 3.5 * * Released under version 2 of the Gnu Public License. * By Chris Brady - * ---------------------------------------------------- - * MemTest86+ V4.00 Specific code (GPL V2.0) - * By Samuel DEMEULEMEESTER, sdemeule@memtest.org - * http://www.canardpc.com - http://www.memtest.org */ - + +#include "stdint.h" +#include "stddef.h" #include "test.h" #include "defs.h" +#include "cpuid.h" +#include "smp.h" #include "config.h" #undef TEST_TIMES #define DEFTESTS 9 - -extern void bzero(); - -const struct tseq tseq[] = { - {1, 5, 4, 0, "[Address test, walking ones] "}, - {1, 6, 4, 0, "[Address test, own address] "}, - {1, 0, 4, 0, "[Moving inversions, ones & zeros] "}, - {1, 1, 2, 0, "[Moving inversions, 8 bit pattern] "}, - {1, 10, 50, 0, "[Moving inversions, random pattern] "}, - {1, 7, 80, 0, "[Block move, 80 moves] "}, - {1, 2, 2, 0, "[Moving inversions, 32 bit pattern] "}, - {1, 9, 30, 0, "[Random number sequence] "}, - {1, 11, 6, 0, "[Modulo 20, Random pattern] "}, - {1, 8, 1, 0, "[Bit fade test, 90 min, 2 patterns] "}, - {0, 0, 0, 0, NULL} +#define FIRST_DIVISER 3 + +/* The main stack is allocated during boot time. The stack size should + * preferably be a multiple of page size(4Kbytes) +*/ + +extern struct cpu_ident cpu_id; +extern char toupper(char c); +extern int isxdigit(char c); +extern void reboot(); +extern void bzero(); +extern void smp_set_ordinal(int me, int ord); +extern int smp_my_ord_num(int me); +extern int smp_ord_to_cpu(int me); +extern void get_cpuid(); +extern void initialise_cpus(); +extern ulong rand(int cpu); +extern void get_mem_speed(int cpu, int ncpus); +extern void rand_seed(unsigned int seed1, unsigned int seed2, int cpu); +extern struct barrier_s *barr; +extern int num_cpus; +extern int act_cpus; + +static int find_ticks_for_test(int test); +void find_ticks_for_pass(void); +int find_chunks(int test); +static void test_setup(void); +static int compute_segments(struct pmap map, int cpu); +int do_test(int ord); +struct tseq tseq[] = { + {1, -1, 0, 6, 0, "[Address test, walking ones, no cache] "}, + {1, -1, 1, 6, 0, "[Address test, own address Sequential] "}, + {1, 32, 2, 6, 0, "[Address test, own address Parallel] "}, + {1, 32, 3, 6, 0, "[Moving inversions, 1s & 0s Parallel] "}, + {1, 32, 5, 3, 0, "[Moving inversions, 8 bit pattern] "}, + {1, 32, 6, 30, 0, "[Moving inversions, random pattern] "}, + {1, 32, 7, 81, 0, "[Block move] "}, + {1, 1, 8, 3, 0, "[Moving inversions, 32 bit pattern] "}, + {1, 32, 9, 48, 0, "[Random number sequence] "}, + {1, 32, 10, 6, 0, "[Modulo 20, Random pattern] "}, + {1, 1, 11, 240, 0, "[Bit fade test, 2 patterns] "}, + {1, 0, 0, 0, 0, NULL} }; -char firsttime = 0; -char cmdline_parsed = 0; - -struct vars variables = {}; -struct vars * const v = &variables; - -volatile ulong *p = 0; -ulong p1 = 0, p2 = 0, p0 = 0; -int segs = 0, bail = 0; -int test_ticks; -int nticks; -ulong high_test_adr = 0x200000; - -static int window = 0; -static int c_iter; -static struct pmap windows[] = +volatile int mstr_cpu; +volatile int run_cpus; +volatile int cpu_ord=0; +int maxcpus=MAX_CPUS; +volatile short cpu_sel; +volatile short cpu_mode; +char cpu_mask[MAX_CPUS]; +long bin_mask=0xffffffff; +short onepass; +volatile short btflag = 0; +volatile int test; +short restart_flag; +bool reloc_pending = FALSE; +uint8_t volatile stacks[MAX_CPUS][STACKSIZE]; +int bitf_seq = 0; +char cmdline_parsed = 0; +struct vars variables = {}; +struct vars * const v = &variables; +volatile int bail; +int nticks; +int test_ticks; +volatile int segs; +static int ltest; +static int pass_flag = 0; +volatile short start_seq = 0; +static int c_iter; +ulong high_test_adr; +volatile static int window; +volatile static unsigned long win_next; +volatile static ulong win0_start; /* Start test address for window 0 */ +volatile static ulong win1_end; /* End address for relocation */ +volatile static struct pmap winx; /* Window struct for mapping windows */ + +/* Find the next selected test to run */ +void next_test() { - { 0, 0x080000 }, - { 0, 0 }, - - { 0x080000, 0x100000 }, - { 0x100000, 0x180000 }, - { 0x180000, 0x200000 }, - - { 0x200000, 0x280000 }, - { 0x280000, 0x300000 }, - - { 0x300000, 0x380000 }, - { 0x380000, 0x400000 }, - - { 0x400000, 0x480000 }, - { 0x480000, 0x500000 }, - - { 0x500000, 0x580000 }, - { 0x580000, 0x600000 }, - - { 0x600000, 0x680000 }, - { 0x680000, 0x700000 }, - - { 0x700000, 0x780000 }, - { 0x780000, 0x800000 }, + test++; + while (tseq[test].sel == 0 && tseq[test].cpu_sel != 0) { + test++; + } - { 0x800000, 0x880000 }, - { 0x880000, 0x900000 }, + if (tseq[test].cpu_sel == 0) { + /* We hit the end of the list so we completed a pass */ + pass_flag++; + /* Find the next test to run, start searching from 0 */ + test = 0; + while (tseq[test].sel == 0 && tseq[test].cpu_sel != 0) { + test++; + } + } +} - { 0x900000, 0x980000 }, - { 0x980000, 0xA00000 }, +/* Set default values for all parameters */ +void set_defaults() +{ + int i; - { 0xA00000, 0xA80000 }, - { 0xA80000, 0xB00000 }, + if (start_seq == 2) { + /* This is a restart so we reset everything */ + onepass = 0; + i = 0; + while (tseq[i].cpu_sel) { + tseq[i].sel = 1; + i++; + } + test = 0; + if (tseq[0].sel == 0) { + next_test(); + } + } + ltest = -1; + win_next = 0; + window = 0; + bail = 0; + cpu_mode = CPM_ALL; + cpu_sel = 0; + v->printmode=PRINTMODE_ADDRESSES; + v->numpatn=0; + v->plim_lower = 0; + v->plim_upper = v->pmap[v->msegs-1].end; + v->pass = 0; + v->msg_line = 0; + v->ecount = 0; + v->ecc_ecount = 0; + v->msg_line = LINE_SCROLL-1; + v->scroll_start = v->msg_line * 160; + v->erri.low_addr.page = 0x7fffffff; + v->erri.low_addr.offset = 0xfff; + v->erri.high_addr.page = 0; + v->erri.high_addr.offset = 0; + v->erri.min_bits = 32; + v->erri.max_bits = 0; + v->erri.min_bits = 32; + v->erri.max_bits = 0; + v->erri.maxl = 0; + v->erri.cor_err = 0; + v->erri.ebits = 0; + v->erri.hdr_flag = 0; + v->erri.tbits = 0; + for (i=0; tseq[i].msg != NULL; i++) { + tseq[i].errors = 0; + } + restart_flag = 0; + tseq[10].sel = 0; +} - { 0xB00000, 0xB80000 }, - { 0xB80000, 0xC00000 }, +/* Boot trace function */ +short tidx = 25; +void btrace(int me, int line, char *msg, int wait, long v1, long v2) +{ + int y, x; - { 0xC00000, 0xC80000 }, - { 0xC80000, 0xD00000 }, + /* Is tracing turned on? */ + if (btflag == 0) return; - { 0xD00000, 0xD80000 }, - { 0xD80000, 0xE00000 }, + spin_lock(&barr->mutex); + y = tidx%13; + x = tidx/13*40; + cplace(y+11, x+1, ' '); + if (++tidx > 25) { + tidx = 0; + } + y = tidx%13; + x = tidx/13*40; + + cplace(y+11, x+1, '>'); + dprint(y+11, x+2, me, 2, 0); + dprint(y+11, x+5, line, 4, 0); + cprint(y+11, x+10, msg); + hprint(y+11, x+22, v1); + hprint(y+11, x+31, v2); + if (wait) { + wait_keyup(); + } + spin_unlock(&barr->mutex); +} - { 0xE00000, 0xE80000 }, - { 0xE80000, 0xF00000 }, +/* Relocate the test to a new address. Be careful to not overlap! */ +static void run_at(unsigned long addr, int cpu) +{ + ulong *ja = (ulong *)(addr + startup_32 - _start); - { 0xF00000, 0xF80000 }, - { 0xF80000, 0x1000000 }, -}; + /* CPU 0, Copy memtest86+ code */ + if (cpu == 0) { + memmove((void *)addr, &_start, _end - _start); + } + /* Wait for the copy */ + barrier(); -#if (LOW_TEST_ADR > (640*1024)) -#error LOW_TEST_ADR must be below 640K -#endif + /* We use a lock to insure that only one CPU at a time jumps to + * the new code. Some of the startup stuff is not thread safe! */ + spin_lock(&barr->mutex); -static int find_ticks_for_test(int ch, int test); -static int compute_segments(int win); -void find_ticks_for_pass(void); + /* Jump to the start address */ + goto *ja; +} -static void __run_at(unsigned long addr) +/* Switch from the boot stack to the main stack. First the main stack + * is allocated, then the contents of the boot stack are copied, then + * ESP is adjusted to point to the new stack. + */ +static void +switch_to_main_stack(unsigned cpu_num) { - /* Copy memtest86+ code */ - memmove((void *)addr, &_start, _end - _start); - /* Jump to the start address */ - p = (ulong *)(addr + startup_32 - _start); - goto *p; + extern uintptr_t boot_stack; + extern uintptr_t boot_stack_top; + uintptr_t *src, *dst; + int offs; + uint8_t * stackAddr, *stackTop; + + stackAddr = (uint8_t *) &stacks[cpu_num][0]; + + stackTop = stackAddr + STACKSIZE; + + src = (uintptr_t*)&boot_stack_top; + dst = (uintptr_t*)stackTop; + do { + src--; dst--; + *dst = *src; + } while ((uintptr_t *)src > (uintptr_t *)&boot_stack); + + offs = (uint8_t *)&boot_stack_top - stackTop; + __asm__ __volatile__ ( + "subl %%eax, %%esp" + : /*no output*/ + : "a" (offs) : "memory" + ); } -static unsigned long run_at_addr = 0xffffffff; -static void run_at(unsigned long addr) +void reloc_internal(int cpu) { - unsigned long start; - unsigned long len; + /* clear variables */ + reloc_pending = FALSE; - run_at_addr = addr; + run_at(LOW_TEST_ADR, cpu); +} - start = (unsigned long) &_start; - len = _end - _start; - if ( ((start < addr) && ((start + len) >= addr)) || - ((addr < start) && ((addr + len) >= start))) { - /* Handle overlap by doing an extra relocation */ - if (addr + len < high_test_adr) { - __run_at(high_test_adr); - } - else if (start + len < addr) { - __run_at(LOW_TEST_ADR); - } - } - __run_at(run_at_addr); +void reloc(void) +{ + bail++; + reloc_pending = TRUE; } /* command line passing using the 'old' boot protocol */ @@ -146,484 +274,927 @@ static void run_at(unsigned long addr) static void parse_command_line(void) { - char *cmdline; + long simple_strtoul(char *cmd, char *ptr, int base); + char *cp, dummy; + int i, j, k; if (cmdline_parsed) return; + /* Fill in the cpu mask array with the default */ + for (i=0; i<MAX_CPUS; i++) { + cpu_mask[i] = 1; + } + if (*OLD_CL_MAGIC_ADDR != OLD_CL_MAGIC) return; unsigned short offset = *OLD_CL_OFFSET_ADDR; - cmdline = MK_PTR(INITSEG, offset); + cp = MK_PTR(INITSEG, offset); /* skip leading spaces */ - while (*cmdline == ' ') - cmdline++; + while (*cp == ' ') + cp++; - while (*cmdline) { - if (!strncmp(cmdline, "console=", 8)) { - cmdline += 8; - serial_console_setup(cmdline); + while (*cp) { + if (!strncmp(cp, "console=", 8)) { + cp += 8; + serial_console_setup(cp); + } + /* Enable boot trace? */ + if (!strncmp(cp, "btrace", 6)) { + cp += 6; + btflag++; } + /* Limit number of CPUs */ + if (!strncmp(cp, "maxcpus=", 8)) { + cp += 8; + maxcpus=(int)simple_strtoul(cp, &dummy, 10); + } + /* Run one pass and exit if there are no errors */ + if (!strncmp(cp, "onepass", 7)) { + cp += 7; + onepass++; + } + /* Setup a list of tests to run */ + if (!strncmp(cp, "tstlist=", 8)) { + cp += 8; + /* Clear all of the tests first */ + k = 0; + while (tseq[k].cpu_sel) { + tseq[k].sel = 0; + k++; + } + /* Now enable all of the tests in the list */ + j = 0; + while(*cp && isdigit(*cp)) { + i = *cp-'0'; + j = j*10 + i; + cp++; + if (*cp == ',' || !isdigit(*cp)) { + if (j < k) { + tseq[j].sel = 1; + } + if (*cp != ',') break; + j = 0; + cp++; + } + } + } + /* Set a CPU mask to select CPU's to use for testing */ + if (!strncmp(cp, "cpumask=", 8)) { + cp += 8; + if (cp[0] == '0' && toupper(cp[1]) == 'X') cp += 2; + while (*cp && *cp != ' ' && isxdigit(*cp)) { + i = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10; + bin_mask = bin_mask * 16 + i; + cp++; + } + /* Force CPU zero to always be selected */ + bin_mask |= 1; + for (i=0; i<32; i++) { + if (((bin_mask>>i) & 1) == 0) { + cpu_mask[i] = 0; + } + } + } /* go to the next parameter */ - while (*cmdline && *cmdline != ' ') - cmdline++; - while (*cmdline == ' ') - cmdline++; + while (*cp && *cp != ' ') cp++; + while (*cp == ' ') cp++; } cmdline_parsed = 1; } - -void do_test(void) +void clear_screen() { - int i = 0, j = 0; - unsigned long chunks; - unsigned long lo, hi; + int i; + char *pp; - parse_command_line(); + /* Clear screen & set background to blue */ + for(i=0, pp=(char *)(SCREEN_ADR); i<80*25; i++) { + *pp++ = ' '; + *pp++ = 0x17; + } + if (btflag) { + cprint(1, 0, "Boot Trace Enabled"); + cprint(1, 0, "Press any key to advance to next trace point"); + cprint(9, 1,"CPU Line Message Param #1 Param #2 CPU Line Message Param #1 Param #2"); + cprint(10,1,"--- ---- ----------- -------- -------- --- ---- ----------- -------- --------"); + } - /* If we have a partial relocation finish it */ - if (run_at_addr == (unsigned long)&_start) { - run_at_addr = 0xffffffff; - } else if (run_at_addr != 0xffffffff) { - __run_at(run_at_addr); +} +/* This is the test entry point. We get here on statup and also whenever + * we relocate. */ +void test_start(void) +{ + int my_cpu_num, my_cpu_ord, run; + + /* If this is the first time here we are CPU 0 */ + if (start_seq == 0) { + my_cpu_num = 0; + } else { + my_cpu_num = smp_my_cpu_num(); } + /* First thing, switch to main stack */ + switch_to_main_stack(my_cpu_num); + + /* First time (for this CPU) initialization */ + if (start_seq < 2) { + + /* These steps are only done by the boot cpu */ + if (my_cpu_num == 0) { + my_cpu_ord = cpu_ord++; + smp_set_ordinal(my_cpu_num, my_cpu_ord); + parse_command_line(); + clear_screen(); + /* Initialize the barrier so the lock in btrace will work. + * Will get redone later when we know how many CPUs we have */ + barrier_init(1); + btrace(my_cpu_num, __LINE__, "Begin ", 1, 0, 0); + /* Find memory size */ + mem_size(); /* must be called before initialise_cpus(); */ + /* Fill in the CPUID table */ + get_cpuid(); + /* Startup the other CPUs */ + start_seq = 1; + //initialise_cpus(); + btrace(my_cpu_num, __LINE__, "BeforeInit", 1, 0, 0); + /* Draw the screen and get system information */ + init(); + + /* Set defaults and initialize variables */ + set_defaults(); + + /* Setup base address for testing, 1 MB */ + win0_start = 0x100; + + /* Set relocation address to 32Mb if there is enough + * memory. Otherwise set it to 3Mb */ + /* Large reloc addr allows for more testing overlap */ + if ((ulong)v->pmap[v->msegs-1].end > 0x2f00) { + high_test_adr = 0x2000000; + } else { + high_test_adr = 0x300000; + } + win1_end = (high_test_adr >> 12); + + /* Adjust the map to not test the page at 939k, + * reserved for locks */ + v->pmap[0].end--; - /* If first time, initialize test */ - if (firsttime == 0) { - if ((ulong)&_start != LOW_TEST_ADR) { - restart(); - } - - init(); - find_ticks_for_pass(); - - windows[0].start = - ( LOW_TEST_ADR + (_end - _start) + 4095) >> 12; + } else { + /* APs only, Register the APs */ + btrace(my_cpu_num, __LINE__, "AP_Start ", 0, my_cpu_num, + cpu_ord); + smp_ap_booted(my_cpu_num); + /* Asign a sequential CPU ordinal to each active cpu */ + spin_lock(&barr->mutex); + my_cpu_ord = cpu_ord++; + smp_set_ordinal(my_cpu_num, my_cpu_ord); + spin_unlock(&barr->mutex); + btrace(my_cpu_num, __LINE__, "AP_Done ", 0, my_cpu_num, + my_cpu_ord); + } - /* Set relocation address at 16Mb if there is enough memory */ - if (v->pmap[v->msegs-1].end > 0x1100) { - high_test_adr = 0x01000000; - } - windows[1].end = (high_test_adr >> 12); - firsttime = 1; + } else { + /* Unlock after a relocation */ + spin_unlock(&barr->mutex); + /* Get the CPU ordinal since it is lost during relocation */ + my_cpu_ord = smp_my_ord_num(my_cpu_num); + btrace(my_cpu_num, __LINE__, "Reloc_Done",0,my_cpu_num,my_cpu_ord); } - bail = 0; - /* Find the memory areas I am going to test */ - compute_segments(window); - if (segs == 0) { - goto skip_window; - } - /* Now map in the window... */ - if (map_page(v->map[0].pbase_addr) < 0) { - goto skip_window; - } + /* A barrier to insure that all of the CPUs are done with startup */ + barrier(); + btrace(my_cpu_num, __LINE__, "1st Barr ", 1, my_cpu_num, my_cpu_ord); + - if ((ulong)&_start > LOW_TEST_ADR) { - /* Relocated so we need to test all selected lower memory */ - v->map[0].start = mapping(v->plim_lower); - -#ifdef USB_WAR - /* We must not touch test below 0x500 memory beacuase - * BIOS USB support clobbers location 0x410 and 0x4e0 - */ - if ((ulong)v->map[0].start < 0x500) { - v->map[0].start = (ulong*)0x500; + /* Setup Memory Management and measure memory speed, we do it here + * because we need all of the available CPUs */ + if (start_seq < 2) { + + /* Enable floating point processing */ + if (cpu_id.fid.bits.fpu) + __asm__ __volatile__ ( + "movl %%cr0, %%eax\n\t" + "andl $0x7, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + : : + : "ax" + ); + if (cpu_id.fid.bits.sse) + __asm__ __volatile__ ( + "movl %%cr4, %%eax\n\t" + "orl $0x00000200, %%eax\n\t" + "movl %%eax, %%cr4\n\t" + : : + : "ax" + ); + + btrace(my_cpu_num, __LINE__, "Mem Mgmnt ", 1, cpu_id.fid.bits.pae, cpu_id.fid.bits.lm); + /* Setup memory management modes */ + /* If we have PAE, turn it on */ + if (cpu_id.fid.bits.pae == 1) { + __asm__ __volatile__( + "movl %%cr4, %%eax\n\t" + "orl $0x00000020, %%eax\n\t" + "movl %%eax, %%cr4\n\t" + : : + : "ax" + ); + cprint(LINE_TITLE+1, COL_MODE, "(PAE Mode)"); + } + /* If this is a 64 CPU enable long mode */ + if (cpu_id.fid.bits.lm == 1) { + __asm__ __volatile__( + "movl $0xc0000080, %%ecx\n\t" + "rdmsr\n\t" + "orl $0x00000100, %%eax\n\t" + "wrmsr\n\t" + : : + : "ax", "cx" + ); + cprint(LINE_TITLE+1, COL_MODE, "(X64 Mode)"); + } + /* Get the memory Speed with all CPUs */ + get_mem_speed(my_cpu_num, num_cpus); } -#endif - cprint(LINE_RANGE, COL_MID+28, " Relocated"); - } else { - cprint(LINE_RANGE, COL_MID+28, " "); - } + /* Set the initialized flag only after all of the CPU's have + * Reached the barrier. This insures that relocation has + * been completed for each CPU. */ + btrace(my_cpu_num, __LINE__, "Start Done", 1, 0, 0); + start_seq = 2; + + /* Loop through all tests */ + while (1) { + /* If the restart flag is set all initial params */ + if (restart_flag) { + set_defaults(); + continue; + } + /* Skip single CPU tests if we are using only one CPU */ + if (tseq[test].cpu_sel == -1 && + (num_cpus == 1 || cpu_mode != CPM_ALL)) { + test++; + continue; + } + + test_setup(); + + /* Loop through all possible windows */ + while (win_next <= ((ulong)v->pmap[v->msegs-1].end + WIN_SZ)) { + + /* Main scheduling barrier */ + cprint(8, my_cpu_num+7, "W"); + btrace(my_cpu_num, __LINE__, "Sched_Barr", 1,window,win_next); + barrier(); + + /* Don't go over the 8TB PAE limit */ + if (win_next > MAX_MEM) { + break; + } - /* Update display of memory segments being tested */ - lo = page_of(v->map[0].start); - hi = page_of(v->map[segs -1].end); - aprint(LINE_RANGE, COL_MID+9, lo); - cprint(LINE_RANGE, COL_MID+14, " - "); - aprint(LINE_RANGE, COL_MID+17, hi); - aprint(LINE_RANGE, COL_MID+23, v->selected_pages); - - -#ifdef TEST_TIMES - { - ulong l, h, t; - - asm __volatile__ ( - "rdtsc\n\t" - "subl %%ebx,%%eax\n\t" - "sbbl %%ecx,%%edx\n\t" - :"=a" (l), "=d" (h) - :"b" (v->snapl), "c" (v->snaph) - ); + /* For the bit fade test, #11, we cannot relocate so bump the + * window to 1 */ + if (tseq[test].pat == 11 && window == 0) { + window = 1; + } - cprint(20, 5, ": :"); - t = h * ((unsigned)0xffffffff / v->clks_msec) / 1000; - t += (l / v->clks_msec) / 1000; - i = t % 60; - dprint(20, 10, i%10, 1, 0); - dprint(20, 9, i/10, 1, 0); - t /= 60; - i = t % 60; - dprint(20, +7, i % 10, 1, 0); - dprint(20, +6, i / 10, 1, 0); - t /= 60; - dprint(20, 0, t, 5, 0); - - asm __volatile__ ("rdtsc":"=a" (v->snapl),"=d" (v->snaph)); - } -#endif - /* Now setup the test parameters based on the current test number */ - /* Figure out the next test to run */ + /* Relocate if required */ + if (window != 0 && (ulong)&_start != LOW_TEST_ADR) { + btrace(my_cpu_num, __LINE__, "Sched_RelL", 1,0,0); + run_at(LOW_TEST_ADR, my_cpu_num); + } + if (window == 0 && v->plim_lower >= win0_start) { + window++; + } + if (window == 0 && (ulong)&_start == LOW_TEST_ADR) { + btrace(my_cpu_num, __LINE__, "Sched_RelH", 1,0,0); + run_at(high_test_adr, my_cpu_num); + } + + /* Decide which CPU(s) to use */ + btrace(my_cpu_num, __LINE__, "Sched_CPU0",1,cpu_sel, + tseq[test].cpu_sel); + run = 1; + switch(cpu_mode) { + case CPM_RROBIN: + case CPM_SEQ: + /* Select a single CPU */ + if (my_cpu_ord == cpu_sel) { + mstr_cpu = cpu_sel; + run_cpus = 1; + } else { + run = 0; + } + break; + case CPM_ALL: + /* Use all CPUs */ + if (tseq[test].cpu_sel == -1) { + /* Round robin through all of the CPUs */ + if (my_cpu_ord == cpu_sel) { + mstr_cpu = cpu_sel; + run_cpus = 1; + } else { + run = 0; + } + } else { + /* Use the number of CPUs specified by the test, + * Starting with zero */ + if (my_cpu_ord >= tseq[test].cpu_sel) { + run = 0; + } + /* Set the master CPU to the highest CPU number + * that has been selected */ + if (act_cpus < tseq[test].cpu_sel) { + mstr_cpu = act_cpus-1; + run_cpus = act_cpus; + } else { + mstr_cpu = tseq[test].cpu_sel-1; + run_cpus = tseq[test].cpu_sel; + } + } + } + btrace(my_cpu_num, __LINE__, "Sched_CPU1",1,run_cpus,run); + barrier(); + dprint(9, 7, run_cpus, 2, 0); + + /* Setup a sub barrier for only the selected CPUs */ + if (my_cpu_ord == mstr_cpu) { + s_barrier_init(run_cpus); + } + + /* Make sure the the sub barrier is ready before proceeding */ + barrier(); + + /* Not selected CPUs go back to the scheduling barrier */ + if (run == 0 ) { + continue; + } + cprint(8, my_cpu_num+7, "-"); + btrace(my_cpu_num, __LINE__, "Sched_Win0",1,window,win_next); + + /* Do we need to exit */ + if(reloc_pending) { + reloc_internal(my_cpu_num); + } + + if (my_cpu_ord == mstr_cpu) { + switch (window) { + /* Special case for relocation */ + case 0: + winx.start = 0; + winx.end = win1_end; + window++; + break; + /* Special case for first segment */ + case 1: + winx.start = win0_start; + winx.end = WIN_SZ; + win_next += WIN_SZ; + window++; + break; + /* For all other windows */ + default: + winx.start = win_next; + win_next += WIN_SZ; + winx.end = win_next; + } + btrace(my_cpu_num,__LINE__,"Sched_Win1",1,winx.start, + winx.end); + + /* Find the memory areas to test */ + segs = compute_segments(winx, my_cpu_num); + } + s_barrier(); + btrace(my_cpu_num,__LINE__,"Sched_Win2",1,segs, + v->map[0].pbase_addr); + + if (segs == 0) { + /* No memory in this window so skip it */ + continue; + } + + /* map in the window... */ + if (map_page(v->map[0].pbase_addr) < 0) { + /* Either there is no PAE or we are at the PAE limit */ + break; + } + + btrace(my_cpu_num, __LINE__, "Strt_Test ",1,my_cpu_num, + my_cpu_ord); + do_test(my_cpu_ord); + btrace(my_cpu_num, __LINE__, "End_Test ",1,my_cpu_num, + my_cpu_ord); + + paging_off(); + + } /* End of window loop */ + + s_barrier(); + btrace(my_cpu_num, __LINE__, "End_Win ",1,test, window); + + /* Setup for the next set of windows */ + win_next = 0; + window = 0; + bail = 0; + + /* Only the master CPU does the end of test housekeeping */ + if (my_cpu_ord != mstr_cpu) { + continue; + } + + /* Special handling for the bit fade test #11 */ + if (tseq[test].pat == 11 && bitf_seq != 6) { + /* Keep going until the sequence is complete. */ + bitf_seq++; + continue; + } else { + bitf_seq = 0; + } + + /* Select advancement of CPUs and next test */ + switch(cpu_mode) { + case CPM_RROBIN: + if (++cpu_sel >= act_cpus) { + cpu_sel = 0; + } + next_test(); + break; + case CPM_SEQ: + if (++cpu_sel >= act_cpus) { + cpu_sel = 0; + next_test(); + } + break; + case CPM_ALL: + if (tseq[test].cpu_sel == -1) + { + /* Do the same test for each CPU */ + if (++cpu_sel >= act_cpus) + { + cpu_sel = 0; + next_test(); + } else { + continue; + } + } else { + next_test(); + } + } //???? + btrace(my_cpu_num, __LINE__, "Next_CPU ",1,cpu_sel,test); + + /* If this was the last test then we finished a pass */ + if (pass_flag) + { + pass_flag = 0; + + v->pass++; + + dprint(LINE_INFO, 49, v->pass, 5, 0); + find_ticks_for_pass(); + ltest = -1; + + if (v->ecount == 0) + { + /* If onepass is enabled and we did not get any errors + * reboot to exit the test */ + if (onepass) { reboot(); } + if (!btflag) cprint(LINE_MSG, COL_MSG-8, "** Pass complete, no errors, press Esc to exit **"); + if(BEEP_END_NO_ERROR) + { + beep(1000); + beep(2000); + beep(1000); + beep(2000); + } + } + } + + bail=0; + } /* End test loop */ +} + + +void test_setup() +{ + static int ltest = -1; + + /* See if a specific test has been selected */ if (v->testsel >= 0) { - v->test = v->testsel; + test = v->testsel; + } + + /* Only do the setup if this is a new test */ + if (test == ltest) { + return; } - + ltest = test; + + /* Now setup the test parameters based on the current test number */ if (v->pass == 0) { - c_iter = tseq[v->test].iter/2; + /* Reduce iterations for first pass */ + c_iter = tseq[test].iter/FIRST_DIVISER; } else { - c_iter = tseq[v->test].iter; + c_iter = tseq[test].iter; } - - dprint(LINE_TST, COL_MID+6, v->test, 2, 1); - cprint(LINE_TST, COL_MID+9, tseq[v->test].msg); - set_cache(tseq[v->test].cache); - /* Compute the number of SPINSZ memory segments */ - chunks = 0; - for(i = 0; i < segs; i++) { - unsigned long len; - len = v->map[i].end - v->map[i].start; - chunks += (len + SPINSZ -1)/SPINSZ; - } - test_ticks = find_ticks_for_test(chunks, v->test); + /* Set the number of iterations. We only do half of the iterations */ + /* on the first pass */ + //dprint(LINE_INFO, 28, c_iter, 3, 0); + test_ticks = find_ticks_for_test(test); nticks = 0; v->tptr = 0; - cprint(1, COL_MID+8, " "); - switch(tseq[v->test].pat) { - /* Now do the testing according to the selected pattern */ - case 0: /* Moving inversions, all ones and zeros (test #2) */ + cprint(LINE_PAT, COL_PAT, " "); + cprint(LINE_PAT, COL_PAT-3, " "); + dprint(LINE_TST, COL_MID+6, tseq[test].pat, 2, 1); + cprint(LINE_TST, COL_MID+9, tseq[test].msg); + cprint(2, COL_MID+8, " "); +} + +/* A couple static variables for when all cpus share the same pattern */ +static ulong sp1, sp2; + +int do_test(int my_ord) +{ + int i=0, j=0; + static int bitf_sleep; + unsigned long p0=0, p1=0, p2=0; + + if (my_ord == mstr_cpu) { + if ((ulong)&_start > LOW_TEST_ADR) { + /* Relocated so we need to test all selected lower memory */ + v->map[0].start = mapping(v->plim_lower); + + /* Good 'ol Legacy USB_WAR */ + if (v->map[0].start < (ulong*)0x500) + { + v->map[0].start = (ulong*)0x500; + } + + cprint(LINE_PAT, COL_MID+25, " R"); + } else { + cprint(LINE_PAT, COL_MID+25, " "); + } + + /* Update display of memory segments being tested */ + p0 = page_of(v->map[0].start); + p1 = page_of(v->map[segs-1].end); + aprint(LINE_RANGE, COL_MID+9, p0); + cprint(LINE_RANGE, COL_MID+14, " - "); + aprint(LINE_RANGE, COL_MID+17, p1); + aprint(LINE_RANGE, COL_MID+25, p1-p0); + cprint(LINE_RANGE, COL_MID+30, " of "); + aprint(LINE_RANGE, COL_MID+34, v->selected_pages); + } + + switch(tseq[test].pat) { + + /* Do the testing according to the selected pattern */ + + case 0: /* Address test, walking ones (test #0) */ + /* Run with cache turned off */ + set_cache(0); + addr_tst1(my_ord); + set_cache(1); + BAILOUT; + break; + + case 1: + case 2: /* Address test, own address (test #1, 2) */ + addr_tst2(my_ord); + BAILOUT; + break; + + case 3: + case 4: /* Moving inversions, all ones and zeros (tests #3, 4) */ p1 = 0; p2 = ~p1; - movinv1(c_iter,p1,p2); + s_barrier(); + movinv1(c_iter,p1,p2,my_ord); BAILOUT; /* Switch patterns */ - p2 = p1; - p1 = ~p2; - movinv1(c_iter,p1,p2); + s_barrier(); + movinv1(c_iter,p2,p1,my_ord); BAILOUT; break; - case 1: /* Moving inversions, 8 bit walking ones and zeros (test #3) */ + case 5: /* Moving inversions, 8 bit walking ones and zeros (test #5) */ p0 = 0x80; for (i=0; i<8; i++, p0=p0>>1) { p1 = p0 | (p0<<8) | (p0<<16) | (p0<<24); p2 = ~p1; - movinv1(c_iter,p1,p2); + s_barrier(); + movinv1(c_iter,p1,p2, my_ord); BAILOUT; /* Switch patterns */ - p2 = p1; - p1 = ~p2; - movinv1(c_iter,p1,p2); + s_barrier(); + movinv1(c_iter,p2,p1, my_ord); BAILOUT } break; + + case 6: /* Random Data (test #6) */ + /* Seed the random number generator */ + if (my_ord == mstr_cpu) { + if (cpu_id.fid.bits.rdtsc) { + asm __volatile__ ("rdtsc":"=a" (sp1),"=d" (sp2)); + } else { + sp1 = 521288629 + v->pass; + sp2 = 362436069 - v->pass; + } + rand_seed(sp1, sp2, 0); + } + + s_barrier(); + for (i=0; i < c_iter; i++) { + if (my_ord == mstr_cpu) { + sp1 = rand(0); + sp2 = ~p1; + } + s_barrier(); + movinv1(2,sp1,sp2, my_ord); + BAILOUT; + } + break; + - case 2: /* Moving inversions, 32 bit shifting pattern (test #6) */ + case 7: /* Block move (test #7) */ + block_move(c_iter, my_ord); + BAILOUT; + break; + + case 8: /* Moving inversions, 32 bit shifting pattern (test #8) */ for (i=0, p1=1; p1; p1=p1<<1, i++) { - movinv32(c_iter,p1, 1, 0x80000000, 0, i); + s_barrier(); + movinv32(c_iter,p1, 1, 0x80000000, 0, i, my_ord); BAILOUT + s_barrier(); movinv32(c_iter,~p1, 0xfffffffe, - 0x7fffffff, 1, i); + 0x7fffffff, 1, i, my_ord); BAILOUT } break; - case 3: /* Modulo 20 check, all ones and zeros (unused) */ - p1=0; - for (i=0; i<MOD_SZ; i++) { - p2 = ~p1; - modtst(i, c_iter, p1, p2); - BAILOUT - - /* Switch patterns */ - p2 = p1; - p1 = ~p2; - modtst(i, c_iter, p1,p2); - BAILOUT + case 9: /* Random Data Sequence (test #9) */ + for (i=0; i < c_iter; i++) { + s_barrier(); + movinvr(my_ord); + BAILOUT; } break; - case 4: /* Modulo 20 check, 8 bit pattern (unused) */ - p0 = 0x80; - for (j=0; j<8; j++, p0=p0>>1) { - p1 = p0 | (p0<<8) | (p0<<16) | (p0<<24); + case 10: /* Modulo 20 check, Random pattern (test #10) */ + for (j=0; j<c_iter; j++) { + p1 = rand(0); for (i=0; i<MOD_SZ; i++) { p2 = ~p1; - modtst(i, c_iter, p1, p2); + s_barrier(); + modtst(i, 2, p1, p2, my_ord); BAILOUT /* Switch patterns */ - p2 = p1; - p1 = ~p2; - modtst(i, c_iter, p1, p2); + s_barrier(); + modtst(i, 2, p2, p1, my_ord); BAILOUT } } break; - case 5: /* Address test, walking ones (test #0) */ - addr_tst1(); - BAILOUT; - break; - case 6: /* Address test, own address (test #1) */ - addr_tst2(); - BAILOUT; - break; - - case 7: /* Block move (test #5) */ - block_move(c_iter); - BAILOUT; - break; - case 8: /* Bit fade test (test #9) */ - if (window == 0 ) { - bit_fade(); + case 11: /* Bit fade test, fill (test #11) */ + /* Use a sequence to process all windows for each stage */ + switch(bitf_seq) { + case 0: /* Fill all of memory 0's */ + bit_fade_fill(0, my_ord); + bitf_sleep = 1; + break; + case 1: /* Sleep for the specified time */ + /* Only sleep once */ + if (bitf_sleep) { + sleep(c_iter, 1, my_ord, 0); + bitf_sleep = 0; + } + break; + case 2: /* Now check all of memory for changes */ + bit_fade_chk(0, my_ord); + break; + case 3: /* Fill all of memory 1's */ + bit_fade_fill(-1, my_ord); + bitf_sleep = 1; + break; + case 4: /* Sleep for the specified time */ + /* Only sleep once */ + if (bitf_sleep) { + sleep(c_iter, 1, my_ord, 0); + bitf_sleep = 0; + } + break; + case 5: /* Now check all of memory for changes */ + bit_fade_chk(-1, my_ord); + break; } BAILOUT; break; - case 9: /* Random Data Sequence (test #7) */ - for (i=0; i < c_iter; i++) { - movinvr(); - BAILOUT; - } - break; - case 10: /* Random Data (test #4) */ - for (i=0; i < c_iter; i++) { - p1 = rand(); + + case 90: /* Modulo 20 check, all ones and zeros (unused) */ + p1=0; + for (i=0; i<MOD_SZ; i++) { p2 = ~p1; - movinv1(2,p1,p2); - BAILOUT; + modtst(i, c_iter, p1, p2, my_ord); + BAILOUT + + /* Switch patterns */ + p2 = p1; + p1 = ~p2; + modtst(i, c_iter, p1,p2, my_ord); + BAILOUT } break; - case 11: /* Modulo 20 check, Random pattern (test #8) */ - for (j=0; j<c_iter; j++) { - p1 = rand(); + case 91: /* Modulo 20 check, 8 bit pattern (unused) */ + p0 = 0x80; + for (j=0; j<8; j++, p0=p0>>1) { + p1 = p0 | (p0<<8) | (p0<<16) | (p0<<24); for (i=0; i<MOD_SZ; i++) { p2 = ~p1; - modtst(i, 2, p1, p2); + modtst(i, c_iter, p1, p2, my_ord); BAILOUT /* Switch patterns */ p2 = p1; p1 = ~p2; - modtst(i, 2, p1, p2); + modtst(i, c_iter, p1, p2, my_ord); BAILOUT } } break; } - skip_window: - if (bail) { - goto bail_test; - } - /* Rever to the default mapping and enable the cache */ - paging_off(); - set_cache(1); - window++; - if (window >= sizeof(windows)/sizeof(windows[0])) { - window = 0; - } - /* We finished the test so clear the pattern */ - cprint(LINE_PAT, COL_PAT, " "); - if (window != 0) { - /* Relocate and run the high copy if: - * - The window overwrites us. - * The lower limit is less than START_ADR - * - There is more than 1 meg of memory - */ - if (windows[window].start < - ((ulong)&_start + (_end - _start)) >> 12) { - if (v->pmap[v->msegs-1].end > - (((high_test_adr + (_end - _start)) >> 12)+1)) { - /* We need the high copy and we have enough - * memory so use it. - */ - run_at(high_test_adr); - } else { - /* We can't use this window so skip it */ - goto skip_window; - } - } else { - /* We don't need the high copy for this test */ - run_at(LOW_TEST_ADR); - } - } - else { - /* We have run this test in all of the windows - * advance to the next test. - */ - skip_test: - v->test++; - bail_test: - /* Revert to the default mapping - * and enable the cache. - */ - paging_off(); - set_cache(1); - check_input(); - window = 0; - cprint(LINE_PAT, COL_PAT-3, " "); - /* If this was the last test then we finished a pass */ - if (v->test >= 9 || v->testsel >= 0) { - v->pass++; - dprint(LINE_INFO, COL_PASS, v->pass, 5, 0); - v->test = 0; - v->total_ticks = 0; - v->pptr = 0; - cprint(0, COL_MID+8, - " "); - if (v->ecount == 0 && v->testsel < 0) { - cprint(LINE_MSG+5, 0, - " *****Pass complete, no errors, press Esc to exit***** "); - if(BEEP_END_NO_ERROR) { - beep(1000); - beep(2000); - beep(1000); - beep(2000); - } - } - } - - /* We always start a pass with the low copy */ - run_at(LOW_TEST_ADR); - } + return(0); } -void restart() +/* Compute number of SPINSZ chunks being tested */ +int find_chunks(int tst) { - int i; - volatile char *pp; + int i, j, sg, wmax, ch; + struct pmap twin={0,0}; + unsigned long wnxt = WIN_SZ; + unsigned long len; - /* clear variables */ - firsttime = 0; - v->test = 0; - v->pass = 0; - v->msg_line = 0; - v->ecount = 0; - v->ecc_ecount = 0; + wmax = MAX_MEM/WIN_SZ+2; /* The number of 2 GB segments +2 */ + /* Compute the number of SPINSZ memory segments */ + ch = 0; + for(j = 0; j < wmax; j++) { + /* special case for relocation */ + if (j == 0) { + twin.start = 0; + twin.end = win1_end; + } + + /* special case for first 2 GB */ + if (j == 1) { + twin.start = win0_start; + twin.end = WIN_SZ; + } + + /* For all other windows */ + if (j > 1) { + twin.start = wnxt; + wnxt += WIN_SZ; + twin.end = wnxt; + } + + /* Find the memory areas I am going to test */ + sg = compute_segments(twin, -1); + for(i = 0; i < sg; i++) { + len = v->map[i].end - v->map[i].start; - /* Clear the screen */ - for(i=0, pp=(char *)(SCREEN_ADR+0); i<80*24; i++, pp+=2) { - *pp = ' '; + if (cpu_mode == CPM_ALL && num_cpus > 1) { + switch(tseq[tst].pat) { + case 2: + case 4: + case 5: + case 6: + case 9: + case 10: + len /= act_cpus; + break; + case 7: + case 8: + len /= act_cpus; + break; + } + } + ch += (len + SPINSZ -1)/SPINSZ; + } } - run_at(LOW_TEST_ADR); + return(ch); } +/* Compute the total number of ticks per pass */ void find_ticks_for_pass(void) { - int i, j, chunks; + int i; v->pptr = 0; - - /* Compute the number of SPINSZ memory segments in one pass */ - chunks = 0; - for(j = 0; j < sizeof(windows)/sizeof(windows[0]); j++) { - compute_segments(j); - for(i = 0; i < segs; i++) { - unsigned long len; - len = v->map[i].end - v->map[i].start; - chunks += (len + SPINSZ -1)/SPINSZ; - } - } - compute_segments(window); - window = 0; - for (v->pass_ticks=0, i=0; ((i<DEFTESTS) && (DEFTESTS != NULL)); i++) { - - /* Test to see if this test is selected for execution */ - if (v->testsel >= 0) { - if (i != v->testsel) { - continue; - } + v->pass_ticks = 0; + v->total_ticks = 0; + cprint(1, COL_MID+8, " "); + i = 0; + while (tseq[i].cpu_sel != 0) { + /* Skip tests 2 and 4 if we are using 1 cpu */ + if (act_cpus == 1 && (i == 2 || i == 4)) { + i++; + continue; } - v->pass_ticks += find_ticks_for_test(chunks, i); + v->pass_ticks += find_ticks_for_test(i); + i++; } } - -static int find_ticks_for_test(int ch, int test) +static int find_ticks_for_test(int tst) { - int ticks=0, c; + int ticks=0, c, ch; - /* Set the number of iterations. We only do half of the iterations */ + if (tseq[tst].sel == 0) { + return(0); + } + + /* Determine the number of chunks for this test */ + ch = find_chunks(tst); + + /* Set the number of iterations. We only do 1/2 of the iterations */ /* on the first pass */ - if (v->pass == 0 && FIRST_PASS_HALF_ITERATIONS) { - c = tseq[test].iter/2; + if (v->pass == 0) { + c = tseq[tst].iter/FIRST_DIVISER; } else { - c = tseq[test].iter; + c = tseq[tst].iter; } - switch(tseq[test].pat) { - case 0: /* Moving inversions, all ones and zeros (test #2) */ - ticks = 2 + 4 * c; + switch(tseq[tst].pat) { + case 0: /* Address test, walking ones */ + ticks = 2; break; - case 1: /* Moving inversions, 8 bit walking ones and zeros (test #3) */ - ticks = 24 + 24 * c; + case 1: /* Address test, own address */ + case 2: + ticks = 2; break; - case 2: /* Moving inversions, 32 bit shifting pattern, very long */ - ticks = (1 + c * 2) * 80; + case 3: /* Moving inversions, all ones and zeros */ + case 4: + ticks = 2 + 4 * c; break; - case 3: /* Modulo 20 check, all ones and zeros (unused) */ - ticks = (2 + c) * 40; + case 5: /* Moving inversions, 8 bit walking ones and zeros */ + ticks = 24 + 24 * c; break; - case 4: /* Modulo 20 check, 8 bit pattern (unused) */ - ticks = (2 + c) * 40 * 8; + case 6: /* Random Data */ + ticks = c + 4 * c; break; - case 5: /* Address test, walking ones (test #0) */ - ticks = 4; + case 7: /* Block move */ + ticks = (ch + ch/act_cpus + c*ch); break; - case 6: /* Address test, own address (test #1) */ - ticks = 2; + case 8: /* Moving inversions, 32 bit shifting pattern */ + ticks = (1 + c * 2) * 64; break; - case 7: /* Block move (test #5) */ - ticks = 2 + c; + case 9: /* Random Data Sequence */ + ticks = 3 * c; break; - case 8: /* Bit fade test (test #9) */ - ticks = 1; + case 10: /* Modulo 20 check, Random pattern */ + ticks = 4 * 40 * c; break; - case 9: /* Random Data Sequence (test #7) */ - ticks = 3 * c; + case 11: /* Bit fade test */ + ticks = c * 2 + 4 * ch; break; - case 10: /* Random Data (test #4) */ - ticks = c + 4 * c; + case 90: /* Modulo 20 check, all ones and zeros (unused) */ + ticks = (2 + c) * 40; break; - case 11: /* Modulo 20 check, Random pattern (test #8) */ - ticks = 4 * 40 * c; + case 91: /* Modulo 20 check, 8 bit pattern (unused) */ + ticks = (2 + c) * 40 * 8; break; } - + if (cpu_mode == CPM_SEQ || tseq[tst].cpu_sel == -1) { + ticks *= act_cpus; + } + if (tseq[tst].pat == 7 || tseq[tst].pat == 11) { + return ticks; + } return ticks*ch; } -static int compute_segments(int win) +static int compute_segments(struct pmap win, int me) { unsigned long wstart, wend; - int i; + int i, sg; /* Compute the window I am testing memory in */ - wstart = windows[win].start; - wend = windows[win].end; - segs = 0; + wstart = win.start; + wend = win.end; + sg = 0; /* Now reduce my window to the area of memory I want to test */ if (wstart < v->plim_lower) { @@ -666,9 +1237,9 @@ static int compute_segments(int win) cprint(LINE_SCROLL+(2*i), 64, ") "); cprint(LINE_SCROLL+(2*i+1), 0, "w("); - hprint(LINE_SCROLL+(2*i+1), 2, windows[win].start); + hprint(LINE_SCROLL+(2*i+1), 2, win.start); cprint(LINE_SCROLL+(2*i+1), 10, ", "); - hprint(LINE_SCROLL+(2*i+1), 12, windows[win].end); + hprint(LINE_SCROLL+(2*i+1), 12, win.end); cprint(LINE_SCROLL+(2*i+1), 20, ") "); cprint(LINE_SCROLL+(2*i+1), 22, "m("); @@ -688,16 +1259,27 @@ static int compute_segments(int win) " "); #endif if ((start < end) && (start < wend) && (end > wstart)) { - v->map[segs].pbase_addr = start; - v->map[segs].start = mapping(start); - v->map[segs].end = emapping(end); + v->map[sg].pbase_addr = start; + v->map[sg].start = mapping(start); + v->map[sg].end = emapping(end); +#if 0 + hprint(LINE_SCROLL+(sg+1), 0, sg); + hprint(LINE_SCROLL+(sg+1), 12, v->map[sg].pbase_addr); + hprint(LINE_SCROLL+(sg+1), 22, start); + hprint(LINE_SCROLL+(sg+1), 32, end); + hprint(LINE_SCROLL+(sg+1), 42, mapping(start)); + hprint(LINE_SCROLL+(sg+1), 52, emapping(end)); + cprint(LINE_SCROLL+(sg+2), 0, + " " + " "); +#endif #if 0 - cprint(LINE_SCROLL+(2*i+1), 54, " sg: "); - hprint(LINE_SCROLL+(2*i+1), 61, sg); + cprint(LINE_SCROLL+(2*i+1), 54, ", sg="); + hprint(LINE_SCROLL+(2*i+1), 59, sg); #endif - segs++; + sg++; } } - return (segs); + return (sg); } diff --git a/major_version b/major_version new file mode 100644 index 0000000..c6aaf52 --- /dev/null +++ b/major_version @@ -0,0 +1 @@ +4.99 diff --git a/make_buildnum.sh b/make_buildnum.sh new file mode 100755 index 0000000..93927cd --- /dev/null +++ b/make_buildnum.sh @@ -0,0 +1,20 @@ +#!sh +# FILE: make_buildnum.sh +version="`sed 's/^ *//' major_version`" +old="`sed 's/^ *//' build.number` +1" +echo $old | bc > build.number.temp +mv build.number.temp build.number +#versión.. +echo "$version`sed 's/^ *//' build.number` - `date`" > version.number +#header +echo "#ifndef BUILD_NUMBER_STR" > build_number.h +echo "#define BUILD_NUMBER_STR \"`sed 's/^ *//' build.number`\"" >> build_number.h +echo "#endif" >> build_number.h + +echo "#ifndef VERSION_STR" >> build_number.h +echo "#define VERSION_STR \"$version`sed 's/^ *//' build.number` - `date`\"" >> build_number.h +echo "#endif" >> build_number.h + +echo "#ifndef VERSION_STR_SHORT" >> build_number.h +echo "#define VERSION_STR_SHORT \"$version`sed 's/^ *//' build.number`\"" >> build_number.h +echo "#endif" >> build_number.h @@ -1,7 +1,7 @@ #!/bin/sh # check to see if the correct tools are installed -for X in wc mkisofs +for X in wc genisoimage do if [ "$(which $X)" = "" ]; then echo "makeiso.sh error: $X is not in your path." >&2 @@ -37,9 +37,9 @@ cd cd echo -e "There is nothing to do here\r\r\nMemtest86+ is located on the bootsector of this CD\r\r\n" > README.TXT echo -e "Just boot from this CD and Memtest86+ will launch" >> README.TXT -mkisofs -A "MKISOFS 1.1.2" -p "Memtest86+ 4.20" -publisher "Samuel D. <sdemeule@memtest.org>" -b boot/memtest.img -c boot/boot.catalog -V "MT410" -o memtest.iso . -mv memtest.iso ../mt420.iso +genisoimage -A "MKISOFS 1.1.2" -p "Memtest86+ 5.01" -publisher "Samuel D. <sdemeule@memtest.org>" -b boot/memtest.img -c boot/boot.catalog -V "MT501" -o memtest.iso . +mv memtest.iso ../mt501.iso cd .. rm -rf cd -echo "Done! Memtest86+ 4.20 ISO is mt420.iso" +echo "Done! Memtest86+ 5.01 ISO is mt501.iso" @@ -10,35 +10,38 @@ short e820_nr; short memsz_mode = SZ_MODE_BIOS; -short firmware = FIRMWARE_UNKNOWN; static ulong alt_mem_k; static ulong ext_mem_k; static struct e820entry e820[E820MAX]; -extern ulong p1, p2; -extern volatile ulong *p; +ulong p1, p2; +ulong *p; static void sort_pmap(void); -static int check_ram(void); -static void memsize_bios(void); +//static void memsize_bios(void); static void memsize_820(void); static void memsize_801(void); static int sanitize_e820_map(struct e820entry *orig_map, - struct e820entry *new_bios, short old_nr); +struct e820entry *new_bios, short old_nr); static void memsize_linuxbios(); -static void memsize_probe(void); -static int check_ram(void); /* * Find out how much memory there is. */ void mem_size(void) { - int i; - v->reserved_pages = 0; + int i, flag=0; v->test_pages = 0; + /* Get the memory size from the BIOS */ + /* Determine the memory map */ + if (query_linuxbios()) { + flag = 1; + } else if (query_pcbios()) { + flag = 2; + } + /* On the first time thru only */ /* Make a copy of the memory info table so that we can re-evaluate */ /* The memory map later */ @@ -52,35 +55,18 @@ void mem_size(void) e820[i].type = mem_info.e820[i].type; } } - - switch (memsz_mode) { - case SZ_MODE_BIOS: - /* Get the memory size from the BIOS */ - memsize_bios(); - break; - case SZ_MODE_PROBE: - /* Probe to find memory */ - memsize_probe(); - cprint(LINE_INFO, COL_MMAP, "Probed"); - break; + if (flag == 1) { + memsize_linuxbios(); + } else if (flag == 2) { + memsize_820(); } + /* Guarantee that pmap entries are in ascending order */ sort_pmap(); v->plim_lower = 0; v->plim_upper = v->pmap[v->msegs-1].end; adj_mem(); - aprint(LINE_INFO, COL_RESERVED, v->reserved_pages); -} - -static void memsize_bios() -{ - if (firmware == FIRMWARE_PCBIOS) { - memsize_820(); - } - else if (firmware == FIRMWARE_LINUXBIOS) { - memsize_linuxbios(); - } } static void sort_pmap(void) @@ -114,6 +100,7 @@ static void memsize_linuxbios(void) n = 0; for (i=0; i < e820_nr; i++) { unsigned long long end; + if (e820[i].type != E820_RAM) { continue; } @@ -125,12 +112,13 @@ static void memsize_linuxbios(void) n++; } v->msegs = n; - cprint(LINE_INFO, COL_MMAP, "LxBIOS"); } static void memsize_820() { int i, n, nr; struct e820entry nm[E820MAX]; + unsigned long long start; + unsigned long long end; /* Clean up, adjust and copy the BIOS-supplied E820-map. */ nr = sanitize_e820_map(e820, nm, e820_nr); @@ -145,8 +133,6 @@ static void memsize_820() n = 0; for (i=0; i<nr; i++) { if (nm[i].type == E820_RAM || nm[i].type == E820_ACPI) { - unsigned long long start; - unsigned long long end; start = nm[i].addr; end = start + nm[i].size; @@ -164,12 +150,18 @@ static void memsize_820() v->pmap[n].end = end >> 12; v->test_pages += v->pmap[n].end - v->pmap[n].start; n++; - } else if (nm[i].type == E820_NVS) { - v->reserved_pages += nm[i].size >> 12; +#if 0 + int epmap = 0; + int lpmap = 0; + if(n > 12) { epmap = 34; lpmap = -12; } + hprint (11+n+lpmap,0+epmap,v->pmap[n-1].start); + hprint (11+n+lpmap,10+epmap,v->pmap[n-1].end); + hprint (11+n+lpmap,20+epmap,v->pmap[n-1].end - v->pmap[n-1].start); + dprint (11+n+lpmap,30+epmap,nm[i].type,0,0); +#endif } } v->msegs = n; - cprint(LINE_INFO, COL_MMAP, " e820"); } static void memsize_801(void) @@ -181,10 +173,8 @@ static void memsize_801(void) if (alt_mem_k < ext_mem_k) { mem_size = ext_mem_k; - cprint(LINE_INFO, COL_MMAP, " e88"); } else { mem_size = alt_mem_k; - cprint(LINE_INFO, COL_MMAP, " e801"); } /* First we map in the first 640k */ v->pmap[0].start = 0; @@ -355,130 +345,3 @@ static int sanitize_e820_map(struct e820entry *orig_map, struct e820entry *new_b } return(new_bios_entry); } - -static void memsize_probe(void) -{ - int i, n; - ulong m_lim; - static unsigned long magic = 0x1234569; - - /* Since all address bits may not be decoded, the search for memory - * must be limited. The max address is found by checking for - * memory wrap from 1MB to 4GB. */ - p1 = (ulong)&magic; - m_lim = 0xfffffffc; - for (p2 = 0x100000; p2; p2 <<= 1) { - p = (ulong *)(p1 + p2); - if (*p == 0x1234569) { - m_lim = --p2; - break; - } - } - - /* Turn on cache */ - set_cache(1); - - /* Find all segments of RAM */ - - i = 0; - v->pmap[i].start = ((ulong)&_end + (1 << 12) - 1) >> 12; - p = (ulong *)(v->pmap[i].start << 12); - - /* Limit search for memory to m_lim and make sure we don't - * overflow the 32 bit size of p. */ - while ((ulong)p < m_lim && (ulong)p >= (ulong)&_end) { - /* - * Skip over reserved memory - */ - if ((ulong)p < RES_END && (ulong)p >= RES_START) { - v->pmap[i].end = RES_START >> 12; - v->test_pages += (v->pmap[i].end - v->pmap[i].start); - p = (ulong *)RES_END; - i++; - v->pmap[i].start = 0; - goto fstart; - } - - if (check_ram() == 0) { - /* ROM or nothing at this address, record end addrs */ - v->pmap[i].end = ((ulong)p) >> 12; - v->test_pages += (v->pmap[i].end - v->pmap[i].start); - i++; - v->pmap[i].start = 0; -fstart: - - /* We get here when there is a gap in memory. - * Loop until we find more ram, the gap is more - * than 32768k or we hit m_lim */ - n = 32768 >> 2; - while ((ulong)p < m_lim && (ulong)p >= (ulong)&_end) { - - /* Skip over video memory */ - if ((ulong)p < RES_END && - (ulong)p >= RES_START) { - p = (ulong *)RES_END; - } - if (check_ram() == 1) { - /* More RAM, record start addrs */ - v->pmap[i].start = (ulong)p >> 12; - break; - } - - /* If the gap is 32768k or more then there - * is probably no more memory so bail out */ - if (--n <= 0) { - p = (ulong *)m_lim; - break; - } - p += 0x1000; - } - } - p += 0x1000; - } - - /* If there is ram right up to the memory limit this will record - * the last address. */ - if (v->pmap[i].start) { - v->pmap[i].end = m_lim >> 12; - v->test_pages += (v->pmap[i].end - v->pmap[i].start); - i++; - } - v->msegs = i; -} - -/* check_ram - Determine if this address points to memory by checking - * for a wrap pattern and then reading and then writing the complement. - * We then check that at least one bit changed in each byte before - * believing that it really is memory. */ - -static int check_ram(void) -{ - int s; - - p1 = *p; - - /* write the complement */ - *p = ~p1; - p2 = *p; - s = 0; - - /* Now make sure a bit changed in each byte */ - if ((0xff & p1) != (0xff & p2)) { - s++; - } - if ((0xff00 & p1) != (0xff00 & p2)) { - s++; - } - if ((0xff0000 & p1) != (0xff0000 & p2)) { - s++; - } - if ((0xff000000 & p1) != (0xff000000 & p2)) { - s++; - } - if (s == 4) { - /* RAM at this address */ - return 1; - } - - return 0; -} diff --git a/memtest.bin.lds b/memtest.bin.lds index 699d2aa..702cdb1 100644 --- a/memtest.bin.lds +++ b/memtest.bin.lds @@ -1,15 +1,15 @@ -OUTPUT_FORMAT("binary")
-OUTPUT_ARCH("i386")
-
-ENTRY(_main);
-SECTIONS {
- . = 0;
- .bootsect : { *(.bootsect) }
- .setup : { *(.setup) }
- .memtest : {
- _start = . ;
- *(.data)
- _end = . ;
- }
- _syssize = (_end - _start + 15) >> 4;
-}
+OUTPUT_FORMAT("binary") +OUTPUT_ARCH("i386") + +ENTRY(_main); +SECTIONS { + . = 0; + .bootsect : { *(.bootsect) } + .setup : { *(.setup) } + .memtest : { + _start = . ; + *(.data) + _end = . ; + } + _syssize = (_end - _start + 15) >> 4; +} diff --git a/memtest.lds b/memtest.lds index 2906a24..bbb190a 100644 --- a/memtest.lds +++ b/memtest.lds @@ -1,11 +1,11 @@ -OUTPUT_FORMAT("elf32-i386");
-OUTPUT_ARCH(i386);
-
-ENTRY(_start);
-SECTIONS {
- . = 0x5000;
- _start = . ;
- .data : {
- *(.data)
- }
-}
+OUTPUT_FORMAT("elf32-i386"); +OUTPUT_ARCH(i386); + +ENTRY(_start); +SECTIONS { + . = 0x10000; + _start = . ; + .data : { + *(.data) + } +} diff --git a/memtest_shared.lds b/memtest_shared.lds index 453916c..603f012 100644 --- a/memtest_shared.lds +++ b/memtest_shared.lds @@ -1,53 +1,53 @@ -OUTPUT_FORMAT("elf32-i386");
-OUTPUT_ARCH(i386);
-
-ENTRY(startup_32);
-SECTIONS {
- . = 0;
- .text : {
- _start = .;
- *(.text)
- *(.text.*)
- *(.plt)
- _etext = . ;
- } = 0x9090
- .rodata : {
- *(.rodata)
- *(.rodata.*)
- }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .hash : { *(.hash) }
- .gnu.hash : { *(.gnu.hash) }
- .dynamic : { *(.dynamic) }
-
- .rel.text : { *(.rel.text .rel.text.*) }
- .rel.rodata : { *(.rel.rodata .rel.rodata.*) }
- .rel.data : { *(.rel.data .rel.data.*) }
- .rel.got : { *(.rel.got .rel.got.*) }
- .rel.plt : { *(.rel.plt .rel.plt.*) }
-
- . = ALIGN(4);
- .data : {
- _data = .;
- *(.data)
- *(.data.*)
- }
- .got : {
- *(.got.plt)
- *(.got)
- _edata = . ;
- }
- . = ALIGN(4);
- .bss : {
- _bss = .;
- *(.dynbss)
- *(.bss)
- *(.bss.*)
- *(COMMON)
- /* _end must be at least 256 byte aligned */
- . = ALIGN(256);
- _end = .;
- }
- /DISCARD/ : { *(*) }
-}
+OUTPUT_FORMAT("elf32-i386"); +OUTPUT_ARCH(i386); + +ENTRY(startup_32); +SECTIONS { + . = 0; + .text : { + _start = .; + *(.text) + *(.text.*) + *(.plt) + _etext = . ; + } = 0x9090 + .rodata : { + *(.rodata) + *(.rodata.*) + } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynamic : { *(.dynamic) } + + .rel.text : { *(.rel.text .rel.text.*) } + .rel.rodata : { *(.rel.rodata .rel.rodata.*) } + .rel.data : { *(.rel.data .rel.data.*) } + .rel.got : { *(.rel.got .rel.got.*) } + .rel.plt : { *(.rel.plt .rel.plt.*) } + + . = ALIGN(4); + .data : { + _data = .; + *(.data) + *(.data.*) + } + .got : { + *(.got.plt) + *(.got) + _edata = . ; + } + . = ALIGN(4); + .bss : { + _bss = .; + *(.dynbss) + *(.bss) + *(.bss.*) + *(COMMON) + /* _end must be at least 256 byte aligned */ + . = ALIGN(256); + _end = .; + } + /DISCARD/ : { *(*) } +} @@ -6,11 +6,31 @@ * Note: the rd* operations modify the parameters directly (without using * pointer indirection), this allows gcc to optimize better */ + +#define __FIXUP_ALIGN ".align 8" +#define __FIXUP_WORD ".quad" +#define EFAULT 14 /* Bad address */ #define rdmsr(msr,val1,val2) \ __asm__ __volatile__("rdmsr" \ : "=a" (val1), "=d" (val2) \ - : "c" (msr)) + : "c" (msr) : "edi") + +/* +#define rdmsr_safe(msr,val1,val2) ({\ + int _rc; \ + __asm__ __volatile__( \ + "1: rdmsr\n2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %5,%2\n; jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " "__FIXUP_ALIGN"\n" \ + ".previous\n" \ + : "=a" (val1), "=d" (val2), "=&r" (_rc) \ + : "c" (msr), "2" (0), "i" (-EFAULT)); \ + _rc; }) +*/ #define wrmsr(msr,val1,val2) \ __asm__ __volatile__("wrmsr" \ @@ -58,6 +78,7 @@ #define MSR_IA32_THERM_INTERRUPT 0x19b #define MSR_IA32_THERM_STATUS 0x19c #define MSR_IA32_MISC_ENABLE 0x1a0 +#define MSR_IA32_TEMPERATURE_TARGET 0x1a2 #define MSR_IA32_DEBUGCTLMSR 0x1d9 #define MSR_IA32_LASTBRANCHFROMIP 0x1db diff --git a/mt86+_loader b/mt86+_loader Binary files differindex 6c77a6f..030ea1a 100644 --- a/mt86+_loader +++ b/mt86+_loader diff --git a/mt86+_loader.asm b/mt86+_loader.asm index 600ebfa..8472262 100644 --- a/mt86+_loader.asm +++ b/mt86+_loader.asm @@ -12,8 +12,8 @@ ; The good thing is that you get a single file which can be ; compressed, for example with http://upx.sf.net/ (UPX). -%define fullsize (164504 + buffer - exeh) - ; 164504 is the size of memtest86+ V4.20, adjust as needed! +%define fullsize (150024 + buffer - exeh) + ; 150024 is the size of memtest86+ V5.01, adjust as needed! %define stacksize 2048 %define stackpara ((stacksize + 15) / 16) @@ -7,7 +7,7 @@ * * By Rick van Rein, vanrein@zonnet.nl * ---------------------------------------------------- - * MemTest86+ V2.00 Specific code (GPL V2.0) + * MemTest86+ V1.60 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.x86-secret.com - http://www.memtest.org */ @@ -3,7 +3,7 @@ * Released under version 2 of the Gnu Public License. * By Chris Brady * ---------------------------------------------------- - * MemTest86+ V4.00 Specific code (GPL V2.0) + * MemTest86+ V5.00 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.x86-secret.com - http://www.memtest.org */ @@ -11,6 +11,8 @@ #include "io.h" #include "pci.h" #include "test.h" +#include "stdint.h" +#include "cpuid.h" #define PCI_CONF_TYPE_NONE 0 #define PCI_CONF_TYPE_1 1 @@ -68,30 +70,36 @@ int pci_conf_write(unsigned bus, unsigned dev, unsigned fn, unsigned reg, unsign { int result; - if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) + if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255 && pci_conf_type != PCI_CONF_TYPE_1)) return -1; result = -1; - switch(pci_conf_type) { - case PCI_CONF_TYPE_1: - outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8); - switch(len) { - case 1: outb(value, 0xCFC + (reg & 3)); result = 0; break; - case 2: outw(value, 0xCFC + (reg & 2)); result = 0; break; - case 4: outl(value, 0xCFC); result = 0; break; - } - break; - case PCI_CONF_TYPE_2: - outb(0xF0 | (fn << 1), 0xCF8); - outb(bus, 0xCFA); - - switch(len) { - case 1: outb(value, PCI_CONF2_ADDRESS(dev, reg)); result = 0; break; - case 2: outw(value, PCI_CONF2_ADDRESS(dev, reg)); result = 0; break; - case 4: outl(value, PCI_CONF2_ADDRESS(dev, reg)); result = 0; break; - } - outb(0, 0xCF8); - break; + + switch(pci_conf_type) + { + case PCI_CONF_TYPE_1: + if(reg < 256){ + outl(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8); + }else{ + outl(PCI_CONF3_ADDRESS(bus, dev, fn, reg), 0xCF8); + } + switch(len) { + case 1: outb(value, 0xCFC + (reg & 3)); result = 0; break; + case 2: outw(value, 0xCFC + (reg & 2)); result = 0; break; + case 4: outl(value, 0xCFC); result = 0; break; + } + break; + case PCI_CONF_TYPE_2: + outb(0xF0 | (fn << 1), 0xCF8); + outb(bus, 0xCFA); + + switch(len) { + case 1: outb(value, PCI_CONF2_ADDRESS(dev, reg)); result = 0; break; + case 2: outw(value, PCI_CONF2_ADDRESS(dev, reg)); result = 0; break; + case 4: outl(value, PCI_CONF2_ADDRESS(dev, reg)); result = 0; break; + } + outb(0, 0xCF8); + break; } return result; } @@ -120,9 +128,9 @@ static int pci_check_direct(void) unsigned char tmpCFB; unsigned int tmpCF8; - if (cpu_id.vend_id[0] == 'A' && cpu_id.type == 15) { + if (cpu_id.vend_id.char_array[0] == 'A' && cpu_id.vers.bits.family == 0xF) { pci_conf_type = PCI_CONF_TYPE_1; - return 0; + return 0; } else { /* Check if configuration type 1 works. */ pci_conf_type = PCI_CONF_TYPE_1; @@ -138,6 +146,7 @@ static int pci_check_direct(void) outl(tmpCF8, 0xCF8); /* Check if configuration type 2 works. */ + pci_conf_type = PCI_CONF_TYPE_2; outb(0x00, 0xCFB); outb(0x00, 0xCF8); @@ -145,6 +154,7 @@ static int pci_check_direct(void) if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 && (pci_sanity_check() == 0)) { outb(tmpCFB, 0xCFB); return 0; + } outb(tmpCFB, 0xCFB); @@ -7,6 +7,7 @@ int pci_conf_write(unsigned bus, unsigned dev, unsigned fn, unsigned reg, unsigned len, unsigned long value); int pci_init(void); +#define MAKE_PCIE_ADDRESS(bus, device, function) (((bus) & 0xFF)<<20) | (((device) & 0x1F)<<15) | (((function) & 0x7)<<12) /* * Under PCI, each device has 256 bytes of configuration address space, diff --git a/precomp.bin b/precomp.bin Binary files differindex 293e15d..affaaab 100755 --- a/precomp.bin +++ b/precomp.bin @@ -1,31 +1,38 @@ +/******************************************************************/ +/* Random number generator */ /* concatenation of following two 16-bit multiply with carry generators */ /* x(n)=a*x(n-1)+carry mod 2^16 and y(n)=b*y(n-1)+carry mod 2^16, */ /* number and carry packed within the same 32 bit integer. */ /******************************************************************/ +#include "stdint.h" +#include "cpuid.h" +#include "smp.h" -unsigned int rand( void ); /* returns a random 32-bit integer */ -void rand_seed( unsigned int, unsigned int ); /* seed the generator */ +/* Keep a separate seed for each CPU */ +/* Space the seeds by at least a cache line or performance suffers big time! */ +static unsigned int SEED_X[MAX_CPUS*16]; +static unsigned int SEED_Y[MAX_CPUS*16]; -/* return a random float >= 0 and < 1 */ -#define rand_float ((double)rand() / 4294967296.0) +unsigned long rand (int cpu) +{ + static unsigned int a = 18000, b = 30903; + int me; -static unsigned int SEED_X = 521288629; -static unsigned int SEED_Y = 362436069; + me = cpu*16; + SEED_X[me] = a*(SEED_X[me]&65535) + (SEED_X[me]>>16); + SEED_Y[me] = b*(SEED_Y[me]&65535) + (SEED_Y[me]>>16); -unsigned int rand () - { - static unsigned int a = 18000, b = 30903; + return ((SEED_X[me]<<16) + (SEED_Y[me]&65535)); +} - SEED_X = a*(SEED_X&65535) + (SEED_X>>16); - SEED_Y = b*(SEED_Y&65535) + (SEED_Y>>16); - return ((SEED_X<<16) + (SEED_Y&65535)); - } +void rand_seed( unsigned int seed1, unsigned int seed2, int cpu) +{ + int me; + me = cpu*16; + SEED_X[me] = seed1; + SEED_Y[me] = seed2; +} -void rand_seed( unsigned int seed1, unsigned int seed2 ) - { - if (seed1) SEED_X = seed1; /* use default seeds if parameter is 0 */ - if (seed2) SEED_Y = seed2; - } @@ -1,7 +1,12 @@ -#include <stddef.h> +/* reloc.c - MemTest-86 Version 3.3 + * + * Released under version 2 of the Gnu Public License. + * By Eric Biederman + */ + +#include "stddef.h" #include "stdint.h" #include "elf.h" -#include <string.h> #define __ELF_NATIVE_CLASS 32 #define ELF_MACHINE_NO_RELA 1 @@ -22,7 +27,7 @@ bootstrap relocation instead of general-purpose relocation. */ #define RTLD_BOOTSTRAP -struct link_map +struct link_map { ElfW(Addr) l_addr; /* Current load address */ ElfW(Addr) ll_addr; /* Last load address */ @@ -127,7 +132,7 @@ elf_get_dynamic_info(ElfW(Dyn) *dyn, ElfW(Addr) l_addr, { if (! dyn) return; - + while (dyn->d_tag != DT_NULL) { if (dyn->d_tag < DT_NUM) @@ -142,8 +147,8 @@ elf_get_dynamic_info(ElfW(Dyn) *dyn, ElfW(Addr) l_addr, assert (! "bad dynamic tag"); ++dyn; } - - if (info[DT_PLTGOT] != NULL) + + if (info[DT_PLTGOT] != NULL) info[DT_PLTGOT]->d_un.d_ptr += l_addr; if (info[DT_STRTAB] != NULL) info[DT_STRTAB]->d_un.d_ptr += l_addr; @@ -194,7 +199,7 @@ elf_dynamic_do_rel (struct link_map *map, const ElfW(Sym) *const symtab = (const void *) map->l_info[DT_SYMTAB]->d_un.d_ptr; - + for (; r < end; ++r) { elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], (void *) (map->l_addr + r->r_offset)); @@ -221,32 +226,32 @@ void _dl_start(void) /* Figure out the run-time load address of the dynamic linker itself. */ last_load_address = map.l_addr = elf_machine_load_address(); - + /* Read our own dynamic section and fill in the info array. */ map.l_ld = (void *)map.l_addr + elf_machine_dynamic(); elf_get_dynamic_info (map.l_ld, map.l_addr - map.ll_addr, map.l_info); /* Relocate ourselves so we can do normal function calls and - * data access using the global offset table. + * data access using the global offset table. */ #if !ELF_MACHINE_NO_REL - elf_dynamic_do_rel(&map, + elf_dynamic_do_rel(&map, map.l_info[DT_REL]->d_un.d_ptr, map.l_info[DT_RELSZ]->d_un.d_val); if (map.l_info[DT_PLTREL]->d_un.d_val == DT_REL) { - elf_dynamic_do_rel(&map, + elf_dynamic_do_rel(&map, map.l_info[DT_JMPREL]->d_un.d_ptr, map.l_info[DT_PLTRELSZ]->d_un.d_val); } #endif #if !ELF_MACHINE_NO_RELA - elf_dynamic_do_rela(&map, + elf_dynamic_do_rela(&map, map.l_info[DT_RELA]->d_un.d_ptr, map.l_info[DT_RELASZ]->d_un.d_val); if (map.l_info[DT_PLTREL]->d_un.d_val == DT_RELA) { - elf_dynamic_do_rela(&map, + elf_dynamic_do_rela(&map, map.l_info[DT_JMPREL]->d_un.d_ptr, map.l_info[DT_PLTRELSZ]->d_un.d_val); } diff --git a/screen_buffer.c b/screen_buffer.c index 44635a7..f9e01be 100644 --- a/screen_buffer.c +++ b/screen_buffer.c @@ -1,24 +1,17 @@ -/* --*- C -*-- - * - * By Jani Averbach, Jaa@iki.fi, 2001 +/* screen_buffer.c - MemTest-86 Version 3.3 * * Released under version 2 of the Gnu Public License. - * - * $Author: jaa $ - * $Revision: 1.10 $ - * $Date: 2001/03/29 09:00:30 $ - * $Source: /home/raid/cvs/memtest86/screen_buffer.c,v $ (for CVS) - * + * By Jani Averbach, Jaa@iki.fi, 2001 */ + #include "test.h" #include "screen_buffer.h" - #define SCREEN_X 80 #define SCREEN_Y 25 #define Y_SIZE SCREEN_Y /* - * X-size should by one of by screen size, + * X-size should by one of by screen size, * so that there is room for ending '\0' */ #define X_SIZE SCREEN_X+1 @@ -41,8 +34,8 @@ char get_scrn_buf(const int y, const int x) { - CHECK_BOUNDS(y,x); - return screen_buf[y][x]; + CHECK_BOUNDS(y,x); + return screen_buf[y][x]; } @@ -51,43 +44,43 @@ set_scrn_buf(const int y, const int x, const char val) { - CHECK_BOUNDS(y,x); - screen_buf[y][x] = val; + CHECK_BOUNDS(y,x); + screen_buf[y][x] = val; } void clear_screen_buf() { - int y, x; - - for (y=0; y < SCREEN_Y; ++y){ - for (x=0; x < SCREEN_X; ++x){ - CHECK_BOUNDS(y,x); - screen_buf[y][x] = ' '; - } - CHECK_BOUNDS(y,SCREEN_X); - screen_buf[y][SCREEN_X] = '\0'; - } + int y, x; + + for (y=0; y < SCREEN_Y; ++y){ + for (x=0; x < SCREEN_X; ++x){ + CHECK_BOUNDS(y,x); + screen_buf[y][x] = ' '; + } + CHECK_BOUNDS(y,SCREEN_X); + screen_buf[y][SCREEN_X] = '\0'; + } } -void tty_print_region(const int pi_top, +void tty_print_region(const int pi_top, const int pi_left, const int pi_bottom, const int pi_right) { - int y; - char tmp; + int y; + char tmp; - for (y=pi_top; y < pi_bottom; ++y){ - CHECK_BOUNDS(y, pi_right); + for (y=pi_top; y < pi_bottom; ++y){ + CHECK_BOUNDS(y, pi_right); + + tmp = screen_buf[y][pi_right]; + screen_buf[y][pi_right] = '\0'; - tmp = screen_buf[y][pi_right]; - screen_buf[y][pi_right] = '\0'; + CHECK_BOUNDS(y, pi_left); + ttyprint(y, pi_left, &(screen_buf[y][pi_left])); - CHECK_BOUNDS(y, pi_left); - ttyprint(y, pi_left, &(screen_buf[y][pi_left])); - - screen_buf[y][pi_right] = tmp; - } + screen_buf[y][pi_right] = tmp; + } } void tty_print_line( @@ -112,23 +105,23 @@ void tty_print_line( void tty_print_screen(void) { #ifdef SCRN_DEBUG - int i; + int i; - for (i=0; i < SCREEN_Y; ++i) - ttyprint(i,0, padding); + for (i=0; i < SCREEN_Y; ++i) + ttyprint(i,0, padding); #endif /* SCRN_DEBUG */ - tty_print_region(0, 0, SCREEN_Y, SCREEN_X); + tty_print_region(0, 0, SCREEN_Y, SCREEN_X); } void print_error(char *pstr) { #ifdef SCRN_DEBUG - ttyprint(0,0, padding); + ttyprint(0,0, padding); #endif /* SCRN_DEBUG */ - ttyprint(0,35, pstr); - - while(1); + ttyprint(0,35, pstr); + + while(1); } diff --git a/screen_buffer.h b/screen_buffer.h index a843acc..8ceba03 100644 --- a/screen_buffer.h +++ b/screen_buffer.h @@ -4,11 +4,6 @@ * * Released under version 2 of the Gnu Public License. * - * $Author: jaa $ - * $Revision: 1.6 $ - * $Date: 2001/03/29 09:00:30 $ - * $Source: /home/raid/cvs/memtest86/screen_buffer.h,v $ (for CVS) - * */ #ifndef SCREEN_BUFFER_H_1D10F83B_INCLUDED #define SCREEN_BUFFER_H_1D10F83B_INCLUDED @@ -1,147 +1,154 @@ -/*
- * setup.s is responsible for getting the system data from the BIOS,
- * and putting them into the appropriate places in system memory.
- * both setup.s and system has been loaded by the bootblock.
- *
- * 1-Jan-96 Modified by Chris Brady for use as a boot/loader for memtest-86.
- */
-
-#define __ASSEMBLY__
-#include "defs.h"
-
-.code16
-.section ".setup", "ax", @progbits
-.globl start
-start:
-# ok, the read went well
-# now we want to move to protected mode ...
-
-
- cli # no interrupts allowed #
- movb $0x80, %al # disable NMI for the bootup sequence
- outb %al, $0x70
-
-
-# The system will move itself to its rightful place.
-
- push %cs
- pop %ds
- lidt idt_48 - start # load idt with 0,0
- lgdt gdt_48 - start # load gdt with whatever appropriate
-
-# that was painless, now we enable A20
-# start from grub-a20.patch
- /*
- * try to switch gateA20 using PORT92, the "Fast A20 and Init"
- * register
- */
- mov $0x92, %dx
- inb %dx, %al
- /* skip the port92 code if it's unimplemented (read returns 0xff) */
- cmpb $0xff, %al
- jz alt_a20_done
-
- /* set or clear bit1, the ALT_A20_GATE bit */
- movb 4(%esp), %ah
- testb %ah, %ah
- jz alt_a20_cont1
- orb $2, %al
- jmp alt_a20_cont2
-alt_a20_cont1:
- and $0xfd, %al
-
- /* clear the INIT_NOW bit; don't accidently reset the machine */
-alt_a20_cont2:
- and $0xfe, %al
- outb %al, %dx
-
-alt_a20_done:
-# end from grub-a20.patch
-
- call empty_8042
-
- movb $0xD1, %al # command write
- outb %al, $0x64
- call empty_8042
-
- movb $0xDF, %al # A20 on
- outb %al, $0x60
- call empty_8042
-
-/*
- * Note that the short jump isn't strictly needed, althought there are
- * reasons why it might be a good idea. It won't hurt in any case.
- */
- movw $0x0001, %ax # protected mode (PE) bit
- lmsw %ax # This is it#
- jmp flush_instr
-flush_instr:
- movw $KERNEL_DS, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw %ax, %fs
- movw %ax, %gs
-
-data32 ljmp $KERNEL_CS, $(TSTLOAD <<4) # jmp offset 2000 of segment 0x10 (cs)
-
-/*
- * This routine checks that the keyboard command queue is empty
- * (after emptying the output buffers)
- *
- * No timeout is used - if this hangs there is something wrong with
- * the machine, and we probably couldn't proceed anyway.
- */
-empty_8042:
- call delay
- inb $0x64, %al # 8042 status port
- cmpb $0xff, %al # from grub-a20-patch, skip if not impl
- jz empty_8042_ret
-
- testb $1, %al # output buffer?
- jz no_output
- call delay
- inb $0x60, %al # read it
- jmp empty_8042
-
-no_output:
- testb $2, %al # is input buffer full?
- jnz empty_8042 # yes - loop
-empty_8042_ret:
- ret
-#
-# Delay is needed after doing i/o
-#
-delay:
- .word 0x00eb # jmp $+2
- ret
-
-gdt:
- .word 0,0,0,0 # dummy
-
- .word 0,0,0,0 # unused
-
- .word 0x7FFF # limit 128mb
- .word 0x0000 # base address=0
- .word 0x9A00 # code read/exec
- .word 0x00C0 # granularity=4096, 386
-
- .word 0x7FFF # limit 128mb
- .word 0x0000 # base address=0
- .word 0x9200 # data read/write
- .word 0x00C0 # granularity=4096, 386
-
-idt_48:
- .word 0 # idt limit=0
- .long 0 # idt base=0L
-
-gdt_48:
- .word 0x800 # gdt limit=2048, 256 GDT entries
- .word 512+gdt - start,0x9 # gdt base = 0X9xxxx
-
-msg1:
- .asciz "Setup.S\r\n"
-
- /* Pad setup to the proper size */
- .org (SETUPSECS*512)
-
+/* + * setup.s is responsible for getting the system data from the BIOS, + * and putting them into the appropriate places in system memory. + * both setup.s and system has been loaded by the bootblock. + * + * 1-Jan-96 Modified by Chris Brady for use as a boot/loader for memtest-86. + */ + +#define __ASSEMBLY__ +#include "defs.h" + +.code16 +.section ".setup", "ax", @progbits +.globl start +start: +# ok, the read went well +# now we want to move to protected mode ... + + + cli # no interrupts allowed # + movb $0x80, %al # disable NMI for the bootup sequence + outb %al, $0x70 + +# The system will move itself to its rightful place. +# reload the segment registers and the stack since the +# APs also execute this code +#ljmp $INITSEG, $(reload - start + 0x200) +reload: + movw $INITSEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %ss # reset the stack to INITSEG:0x4000-12. + movw %dx, %sp + push %cs + pop %ds + lidt idt_48 - start # load idt with 0,0 + lgdt gdt_48 - start # load gdt with whatever appropriate + +# that was painless, now we enable A20 +# start from grub-a20.patch + /* + * try to switch gateA20 using PORT92, the "Fast A20 and Init" + * register + */ + mov $0x92, %dx + inb %dx, %al + /* skip the port92 code if it's unimplemented (read returns 0xff) */ + cmpb $0xff, %al + jz alt_a20_done + + /* set or clear bit1, the ALT_A20_GATE bit */ + movb 4(%esp), %ah + testb %ah, %ah + jz alt_a20_cont1 + orb $2, %al + jmp alt_a20_cont2 +alt_a20_cont1: + and $0xfd, %al + + /* clear the INIT_NOW bit; don't accidently reset the machine */ +alt_a20_cont2: + and $0xfe, %al + outb %al, %dx + +alt_a20_done: +# end from grub-a20.patch + + call empty_8042 + + movb $0xD1, %al # command write + outb %al, $0x64 + call empty_8042 + + movb $0xDF, %al # A20 on + outb %al, $0x60 + call empty_8042 + +/* + * Note that the short jump isn't strictly needed, althought there are + * reasons why it might be a good idea. It won't hurt in any case. + */ + movw $0x0001, %ax # protected mode (PE) bit + lmsw %ax # This is it# + jmp flush_instr +flush_instr: + movw $KERNEL_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + +data32 ljmp $KERNEL_CS, $(TSTLOAD <<4) # jmp offset 2000 of segment 0x10 (cs) + +/* + * This routine checks that the keyboard command queue is empty + * (after emptying the output buffers) + * + * No timeout is used - if this hangs there is something wrong with + * the machine, and we probably couldn't proceed anyway. + */ +empty_8042: + call delay + inb $0x64, %al # 8042 status port + cmpb $0xff, %al # from grub-a20-patch, skip if not impl + jz empty_8042_ret + testb $1, %al # output buffer? + jz no_output + call delay + inb $0x60, %al # read it + jmp empty_8042 + +no_output: + testb $2, %al # is input buffer full? + jnz empty_8042 # yes - loop +empty_8042_ret: + ret +# +# Delay is needed after doing i/o +# +delay: + .word 0x00eb # jmp $+2 + ret + +gdt: + .word 0,0,0,0 # dummy + + .word 0,0,0,0 # unused + + .word 0x7FFF # limit 128mb + .word 0x0000 # base address=0 + .word 0x9A00 # code read/exec + .word 0x00C0 # granularity=4096, 386 + + .word 0x7FFF # limit 128mb + .word 0x0000 # base address=0 + .word 0x9200 # data read/write + .word 0x00C0 # granularity=4096, 386 + +idt_48: + .word 0 # idt limit=0 + .long 0 # idt base=0L + +gdt_48: + .word 0x800 # gdt limit=2048, 256 GDT entries + .word 512+gdt - start,0x9 # gdt base = 0X9xxxx + +msg1: + .asciz "Setup.S\r\n" + + /* Pad setup to the proper size */ + .org (SETUPSECS*512) + @@ -1,136 +1,113 @@ /* - * smp.c -- + * MemTest86+ V5 Specific code (GPL V2.0) + * By Samuel DEMEULEMEESTER, sdemeule@memtest.org + * http://www.canardpc.com - http://www.memtest.org + * ------------------------------------------------ + * smp.c - MemTest-86 Version 3.5 * - * Implements support for SMP machines. For reasons of - * simplicity, we do not handle all possible cases allowed by the - * MP spec. For example, we expect an explicit MP configuration - * table and do not handle default configurations. We also expect - * an on-chip local apic and do not support an external 82489DX - * apic controller. - * + * Released under version 2 of the Gnu Public License. + * By Chris Brady */ #include "stddef.h" -#include "smp.h" +#include "stdint.h" #include "cpuid.h" +#include "smp.h" #include "test.h" + #define DELAY_FACTOR 1 +unsigned num_cpus = 1; // There is at least one cpu, the BSP +int act_cpus; +unsigned found_cpus = 0; + extern void memcpy(void *dst, void *src , int len); extern void test_start(void); +extern int run_cpus; +extern int maxcpus; +extern char cpu_mask[]; +extern struct cpu_ident cpu_id; -typedef struct { - bool started; -} ap_info_t; +struct barrier_s *barr; -volatile apic_register_t *APIC = NULL; -unsigned number_of_cpus = 1; // There is at least one cpu, the BSP -/* CPU number to APIC ID mapping table. CPU 0 is the BSP. */ -static unsigned cpu_num_to_apic_id[MAX_CPUS]; -volatile ap_info_t AP[MAX_CPUS]; +void smp_find_cpus(); -uint8_t -checksum(uint8_t *data, unsigned len) +void barrier_init(int max) { - uint32_t sum = 0; - uint8_t *end = data + len; - while (data < end) { - sum += *data; - data++; - } - return (uint8_t)(sum % 0x100); + /* Set the adddress of the barrier structure */ + barr = (struct barrier_s *)0x9ff00; + barr->lck.slock = 1; + barr->mutex.slock = 1; + barr->maxproc = max; + barr->count = max; + barr->st1.slock = 1; + barr->st2.slock = 0; } - -bool -read_mp_config_table(uintptr_t addr) +void s_barrier_init(int max) { - mp_config_table_header_t *mpc = (mp_config_table_header_t*)addr; - uint8_t *tab_entry_ptr; - uint8_t *mpc_table_end; - extern unsigned num_hyper_threads_per_core; - - if (mpc->signature != MPCSignature) { - return FALSE; - } - if (checksum((uint8_t*)mpc, mpc->length) != 0) { - return FALSE; - } - - - /* FIXME: the uintptr_t cast here works around a compilation problem on - * AMD64, but it ignores the real problem, which is that lapic_addr - * is only 32 bits. Maybe that's OK, but it should be investigated. - */ - APIC = (volatile apic_register_t*)(uintptr_t)mpc->lapic_addr; - - tab_entry_ptr = ((uint8_t*)mpc) + sizeof(mp_config_table_header_t); - mpc_table_end = ((uint8_t*)mpc) + mpc->length; - while (tab_entry_ptr < mpc_table_end) { - switch (*tab_entry_ptr) { - case MP_PROCESSOR: { - mp_processor_entry_t *pe = (mp_processor_entry_t*)tab_entry_ptr; - - if (pe->cpu_flag & CPU_BOOTPROCESSOR) { - // BSP is CPU 0 - cpu_num_to_apic_id[0] = pe->apic_id; - } else if (number_of_cpus < MAX_CPUS) { - cpu_num_to_apic_id[number_of_cpus] = pe->apic_id; - number_of_cpus++; - } - if (num_hyper_threads_per_core > 1 ) { - cpu_num_to_apic_id[number_of_cpus] = pe->apic_id | 1; - number_of_cpus++; - } - - // we cannot handle non-local 82489DX apics - if ((pe->apic_ver & 0xf0) != 0x10) { - return 0; - } - - // we don't know what to do with disabled cpus - - tab_entry_ptr += sizeof(mp_processor_entry_t); - break; - } - case MP_BUS: { - tab_entry_ptr += sizeof(mp_bus_entry_t); - break; - } - case MP_IOAPIC: { - tab_entry_ptr += sizeof(mp_io_apic_entry_t); - break; - } - case MP_INTSRC: - tab_entry_ptr += sizeof(mp_interrupt_entry_t); - case MP_LINTSRC: - tab_entry_ptr += sizeof(mp_local_interrupt_entry_t); - break; - default: - return FALSE; - } - } - return TRUE; + barr->s_lck.slock = 1; + barr->s_maxproc = max; + barr->s_count = max; + barr->s_st1.slock = 1; + barr->s_st2.slock = 0; } +void barrier() +{ + if (num_cpus == 1 || v->fail_safe & 3) { + return; + } + spin_wait(&barr->st1); /* Wait if the barrier is active */ + spin_lock(&barr->lck); /* Get lock for barr struct */ + if (--barr->count == 0) { /* Last process? */ + barr->st1.slock = 0; /* Hold up any processes re-entering */ + barr->st2.slock = 1; /* Release the other processes */ + barr->count++; + spin_unlock(&barr->lck); + } else { + spin_unlock(&barr->lck); + spin_wait(&barr->st2); /* wait for peers to arrive */ + spin_lock(&barr->lck); + if (++barr->count == barr->maxproc) { + barr->st1.slock = 1; + barr->st2.slock = 0; + } + spin_unlock(&barr->lck); + } +} -floating_pointer_struct_t * -scan_for_floating_ptr_struct(uintptr_t addr, uint32_t length) +void s_barrier() { - floating_pointer_struct_t *fp; - uintptr_t end = addr + length; + if (run_cpus == 1 || v->fail_safe & 3) { + return; + } + spin_wait(&barr->s_st1); /* Wait if the barrier is active */ + spin_lock(&barr->s_lck); /* Get lock for barr struct */ + if (--barr->s_count == 0) { /* Last process? */ + barr->s_st1.slock = 0; /* Hold up any processes re-entering */ + barr->s_st2.slock = 1; /* Release the other processes */ + barr->s_count++; + spin_unlock(&barr->s_lck); + } else { + spin_unlock(&barr->s_lck); + spin_wait(&barr->s_st2); /* wait for peers to arrive */ + spin_lock(&barr->s_lck); + if (++barr->s_count == barr->s_maxproc) { + barr->s_st1.slock = 1; + barr->s_st2.slock = 0; + } + spin_unlock(&barr->s_lck); + } +} +typedef struct { + bool started; +} ap_info_t; - fp = (floating_pointer_struct_t*)addr; - while ((uintptr_t)fp < end) { - if (fp->signature == FPSignature) { - if (fp->length == 1 && checksum((uint8_t*)fp, 16) == 0) { - return fp; - } - } - fp++; - } - return NULL; -} +volatile apic_register_t *APIC = NULL; +/* CPU number to APIC ID mapping table. CPU 0 is the BSP. */ +static unsigned cpu_num_to_apic_id[MAX_CPUS]; +volatile ap_info_t AP[MAX_CPUS]; void PUT_MEM16(uintptr_t addr, uint16_t val) { @@ -199,7 +176,40 @@ memset (void *dst, *((char *) dst + i) = value; } } +void initialise_cpus(void) +{ + int i; + + act_cpus = 0; + + if (maxcpus > 1) { + smp_find_cpus(); + /* The total number of CPUs may be limited */ + if (num_cpus > maxcpus) { + num_cpus = maxcpus; + } + /* Determine how many cpus have been selected */ + for(i = 0; i < num_cpus; i++) { + if (cpu_mask[i]) { + act_cpus++; + } + } + } else { + act_cpus = found_cpus = num_cpus = 1; + } + + /* Initialize the barrier before starting AP's */ + barrier_init(act_cpus); + + /* let the BSP initialise the APs. */ + for(i = 1; i < num_cpus; i++) { + /* Only start this CPU if it is selected by the mask */ + if (cpu_mask[i]) { + smp_boot_ap(i); + } + } +} void kick_cpu(unsigned cpu_num) { unsigned num_sipi, apic_id; @@ -223,7 +233,7 @@ void kick_cpu(unsigned cpu_num) APIC_WRITE(APICR_ESR, 0); - SEND_IPI(apic_id, 0, 0, APIC_DELMODE_STARTUP, (uint32_t)startup_32 >> 12); + SEND_IPI(apic_id, 0, 0, APIC_DELMODE_STARTUP, (unsigned)startup_32 >> 12); timeout = 0; do { @@ -233,15 +243,15 @@ void kick_cpu(unsigned cpu_num) } while (send_pending && timeout < 1000); if (send_pending) { - //cprint(LINE_STATUS+1, 0, "SMP: STARTUP IPI was never sent"); + cprint(LINE_STATUS+3, 0, "SMP: STARTUP IPI was never sent"); } delay(100000 / DELAY_FACTOR); err = APIC_READ(APICR_ESR) & 0xef; if (err) { - //cprint(LINE_STATUS+1, 0, "SMP: After STARTUP IPI: err = 0x"); - //hprint(LINE_STATUS+1, COL_MID, err); + cprint(LINE_STATUS+3, 0, "SMP: After STARTUP IPI: err = 0x"); + hprint(LINE_STATUS+3, COL_MID, err); } } } @@ -304,91 +314,330 @@ void boot_ap(unsigned cpu_num) } while (send_pending && timeout < 1000); if (send_pending) { - //cprint(LINE_STATUS+1, 0, "SMP: STARTUP IPI was never sent"); + cprint(LINE_STATUS+3, 0, "SMP: STARTUP IPI was never sent"); } delay(100000 / DELAY_FACTOR); err = APIC_READ(APICR_ESR) & 0xef; if (err) { - //cprint(LINE_STATUS+1, 0, "SMP: After STARTUP IPI: err = 0x"); - // hprint(LINE_STATUS+1, COL_MID, err); + cprint(LINE_STATUS+3, 0, "SMP: After STARTUP IPI: err = 0x"); + hprint(LINE_STATUS+3, COL_MID, err); } } } -void -smp_init_bsp() +static int checksum(unsigned char *mp, int len) { - floating_pointer_struct_t *fp; - /* gets the details about the cpu, the type, the brand - * whether it is a multi-core package etc. - */ - cpuid_init(); - - memset(&AP, 0, sizeof AP); + int sum = 0; - fp = scan_for_floating_ptr_struct(0x0, 0x400); - if (fp == NULL) { - fp = scan_for_floating_ptr_struct(639*0x400, 0x400); + while (len--) { + sum += *mp++; } - if (fp == NULL) { - fp = scan_for_floating_ptr_struct(0xf0000, 0x10000); + return (sum & 0xFF); +} + +/* Parse an MP config table for CPU information */ +bool read_mp_config_table(uintptr_t addr) +{ + mp_config_table_header_t *mpc = (mp_config_table_header_t*)addr; + uint8_t *tab_entry_ptr; + uint8_t *mpc_table_end; + + if (mpc->signature != MPCSignature) { + return FALSE; } - if (fp == NULL) { - /* - * If it is an SMP machine we should know now, unless the - * configuration is in an EISA/MCA bus machine with an - * extended bios data area. - * - * there is a real-mode segmented pointer pointing to the - * 4K EBDA area at 0x40E, calculate and scan it here. - */ - unsigned int address = *(unsigned short *)0x40E; - address <<= 4; - if (address) { - fp = scan_for_floating_ptr_struct(address, 0x400); - } + if (checksum((unsigned char*)mpc, mpc->length) != 0) { + return FALSE; } - if (fp != NULL && fp->phys_addr != 0) { - if (!read_mp_config_table(fp->phys_addr)) { - //cprint(LINE_STATUS+1,0, "SMP: Error while parsing MP config table"); + /* FIXME: the uintptr_t cast here works around a compilation problem on + * AMD64, but it ignores the real problem, which is that lapic_addr + * is only 32 bits. Maybe that's OK, but it should be investigated. + */ + APIC = (volatile apic_register_t*)(uintptr_t)mpc->lapic_addr; + + tab_entry_ptr = ((uint8_t*)mpc) + sizeof(mp_config_table_header_t); + mpc_table_end = ((uint8_t*)mpc) + mpc->length; + + while (tab_entry_ptr < mpc_table_end) { + switch (*tab_entry_ptr) { + case MP_PROCESSOR: { + mp_processor_entry_t *pe = (mp_processor_entry_t*)tab_entry_ptr; + + if (pe->cpu_flag & CPU_BOOTPROCESSOR) { + // BSP is CPU 0 + cpu_num_to_apic_id[0] = pe->apic_id; + } else if (num_cpus < MAX_CPUS) { + cpu_num_to_apic_id[num_cpus] = pe->apic_id; + num_cpus++; + } + found_cpus++; + + // we cannot handle non-local 82489DX apics + if ((pe->apic_ver & 0xf0) != 0x10) { + return 0; + } + + tab_entry_ptr += sizeof(mp_processor_entry_t); + break; + } + case MP_BUS: { + tab_entry_ptr += sizeof(mp_bus_entry_t); + break; + } + case MP_IOAPIC: { + tab_entry_ptr += sizeof(mp_io_apic_entry_t); + break; + } + case MP_INTSRC: + tab_entry_ptr += sizeof(mp_interrupt_entry_t); + break; + case MP_LINTSRC: + tab_entry_ptr += sizeof(mp_local_interrupt_entry_t); + break; + default: + return FALSE; } } -/* - if (fp == NULL) { - cprint(LINE_STATUS+1,0,"SMP: No floating pointer structure found"); + return TRUE; +} + +/* Search for a Floating Pointer structure */ +floating_pointer_struct_t * +scan_for_floating_ptr_struct(uintptr_t addr, uint32_t length) +{ + floating_pointer_struct_t *fp; + uintptr_t end = addr + length; + + + while ((uintptr_t)addr < end) { + fp = (floating_pointer_struct_t*)addr; + if (*(unsigned int *)addr == FPSignature && fp->length == 1 && checksum((unsigned char*)addr, 16) == 0 && ((fp->spec_rev == 1) || (fp->spec_rev == 4))) { + return fp; + } + addr += 4; } -*/ + return NULL; } -void -smp_init_aps() +/* Search for a Root System Descriptor Pointer */ +rsdp_t *scan_for_rsdp(uintptr_t addr, uint32_t length) { - int cpuNum; - for(cpuNum = 0 ; cpuNum < MAX_CPUS ; cpuNum++) { - AP[cpuNum].started = FALSE; + rsdp_t *rp; + uintptr_t end = addr + length; + + + while ((uintptr_t)addr < end) { + rp = (rsdp_t*)addr; + if (*(unsigned int *)addr == RSDPSignature && + checksum((unsigned char*)addr, rp->length) == 0) { + return rp; + } + addr += 4; } + return NULL; } -unsigned -my_apic_id() +/* Parse a MADT table for processor entries */ +int parse_madt(uintptr_t addr) { + + mp_config_table_header_t *mpc = (mp_config_table_header_t*)addr; + uint8_t *tab_entry_ptr; + uint8_t *mpc_table_end; + + if (checksum((unsigned char*)mpc, mpc->length) != 0) { + return FALSE; + } + + APIC = (volatile apic_register_t*)(uintptr_t)mpc->lapic_addr; + + tab_entry_ptr = ((uint8_t*)mpc) + sizeof(mp_config_table_header_t); + mpc_table_end = ((uint8_t*)mpc) + mpc->length; + while (tab_entry_ptr < mpc_table_end) { + + madt_processor_entry_t *pe = (madt_processor_entry_t*)tab_entry_ptr; + if (pe->type == MP_PROCESSOR) { + if (pe->enabled) { + if (num_cpus < MAX_CPUS) { + cpu_num_to_apic_id[num_cpus] = pe->apic_id; + + /* the first CPU is the BSP, don't increment */ + if (found_cpus) { + num_cpus++; + } + } + found_cpus++; + } + } + tab_entry_ptr += pe->length; + } + return TRUE; +} + +/* This is where we search for SMP information in the following order + * look for a floating MP pointer + * found: + * check for a default configuration + * found: + * setup config, return + * check for a MP config table + * found: + * validate: + * good: + * parse the MP config table + * good: + * setup config, return + * + * find & validate ACPI RSDP (Root System Descriptor Pointer) + * found: + * find & validate RSDT (Root System Descriptor Table) + * found: + * find & validate MSDT + * found: + * parse the MADT table + * good: + * setup config, return + */ +void smp_find_cpus() +{ + floating_pointer_struct_t *fp; + rsdp_t *rp; + rsdt_t *rt; + uint8_t *tab_ptr, *tab_end; + unsigned int *ptr; + unsigned int uiptr; + + if(v->fail_safe & 3) { return; } + + memset(&AP, 0, sizeof AP); + + if(v->fail_safe & 8) + { + // Search for the Floating MP structure pointer + fp = scan_for_floating_ptr_struct(0x0, 0x400); + if (fp == NULL) { + fp = scan_for_floating_ptr_struct(639*0x400, 0x400); + } + if (fp == NULL) { + fp = scan_for_floating_ptr_struct(0xf0000, 0x10000); + } + if (fp == NULL) { + // Search the BIOS ESDS area + unsigned int address = *(unsigned short *)0x40E; + address <<= 4; + if (address) { + fp = scan_for_floating_ptr_struct(address, 0x400); + } + } + + if (fp != NULL) { + // We have a floating MP pointer + // Is this a default configuration? + + if (fp->feature[0] > 0 && fp->feature[0] <=7) { + // This is a default config so plug in the numbers + num_cpus = 2; + APIC = (volatile apic_register_t*)0xFEE00000; + cpu_num_to_apic_id[0] = 0; + cpu_num_to_apic_id[1] = 1; + return; + } + + // Do we have a pointer to a MP configuration table? + if ( fp->phys_addr != 0) { + if (read_mp_config_table(fp->phys_addr)) { + // Found a good MP table, done + return; + } + } + } + } + + + /* No MP table so far, try to find an ACPI MADT table + * We try to use the MP table first since there is no way to distinguish + * real cores from hyper-threads in the MADT */ + + /* Search for the RSDP */ + rp = scan_for_rsdp(0xE0000, 0x20000); + if (rp == NULL) { + /* Search the BIOS ESDS area */ + unsigned int address = *(unsigned short *)0x40E; + address <<= 4; + if (address) { + rp = scan_for_rsdp(address, 0x400); + } + } + + if (rp == NULL) { + /* RSDP not found, give up */ + return; + } + + /* Found the RSDP, now get either the RSDT or XSDT */ + if (rp->revision >= 2) { + rt = (rsdt_t *)rp->xrsdt[0]; + + if (rt == 0) { + return; + } + // Validate the XSDT + if (*(unsigned int *)rt != XSDTSignature) { + return; + } + if ( checksum((unsigned char*)rt, rt->length) != 0) { + return; + } + + } else { + rt = (rsdt_t *)rp->rsdt; + if (rt == 0) { + return; + } + /* Validate the RSDT */ + if (*(unsigned int *)rt != RSDTSignature) { + return; + } + if ( checksum((unsigned char*)rt, rt->length) != 0) { + return; + } + } + + /* Scan the RSDT or XSDT for a pointer to the MADT */ + tab_ptr = ((uint8_t*)rt) + sizeof(rsdt_t); + tab_end = ((uint8_t*)rt) + rt->length; + + while (tab_ptr < tab_end) { + + uiptr = *((unsigned int *)tab_ptr); + ptr = (unsigned int *)uiptr; + + /* Check for the MADT signature */ + if (ptr && *ptr == MADTSignature) { + /* Found it, now parse it */ + if (parse_madt((uintptr_t)ptr)) { + return; + } + } + tab_ptr += 4; + } +} + +unsigned my_apic_id() { return (APIC[APICR_ID][0]) >> 24; } -void -smp_ap_booted(unsigned cpu_num) +void smp_ap_booted(unsigned cpu_num) { AP[cpu_num].started = TRUE; } -void -smp_boot_ap(unsigned cpu_num) +void smp_boot_ap(unsigned cpu_num) { unsigned timeout; - extern bool smp_mode; + boot_ap(cpu_num); timeout = 0; do { @@ -397,21 +646,13 @@ smp_boot_ap(unsigned cpu_num) } while (!AP[cpu_num].started && timeout < 100000 / DELAY_FACTOR); if (!AP[cpu_num].started) { - //cprint(LINE_STATUS+1, 0, "SMP: Boot timeout for"); - //dprint(LINE_STATUS+1, COL_MID, cpu_num,2,1); - //cprint(LINE_STATUS+1, 26, "Turning off SMP"); - smp_mode = FALSE; + cprint(LINE_STATUS+3, 0, "SMP: Boot timeout for"); + dprint(LINE_STATUS+3, COL_MID, cpu_num,2,1); + cprint(LINE_STATUS+3, 26, "Turning off SMP"); } } -unsigned -smp_num_cpus() -{ - return number_of_cpus; -} - -unsigned -smp_my_cpu_num() +unsigned smp_my_cpu_num() { unsigned apicid = my_apic_id(); unsigned i; @@ -427,14 +668,25 @@ smp_my_cpu_num() return i; } -volatile spinlock_t barr_lk={1}; -void barrier(volatile int *barr, int n) +/* A set of simple functions used to preserve assigned CPU ordinals since + * they are lost after relocation (the stack is reloaded). + */ +int num_to_ord[MAX_CPUS]; +void smp_set_ordinal(int me, int ord) { - spin_lock(&barr_lk); - barr++; - spin_unlock(&barr_lk); - while((uint32_t)barr<n); - barr = 0; - return; + num_to_ord[me] = ord; } +int smp_my_ord_num(int me) +{ + return num_to_ord[me]; +} + +int smp_ord_to_cpu(int me) +{ + int i; + for (i=0; i<MAX_CPUS; i++) { + if (num_to_ord[i] == me) return i; + } + return -1; +}
\ No newline at end of file @@ -7,10 +7,9 @@ #define _SMP_H_ #include "stdint.h" #include "defs.h" -#define MAX_CPUS 16 // "16 CPUs ought to be enough for everybody." +#define MAX_CPUS 32 - -#define FPSignature ('_' | 'M' << 8 | 'P' << 16 | '_' << 24) +#define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24)) typedef struct { uint32_t signature; // "_MP_" @@ -21,7 +20,7 @@ typedef struct { uint8_t feature[5]; } floating_pointer_struct_t; -#define MPCSignature ('P' | 'C' << 8 | 'M' << 16 | 'P' << 24) +#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24)) typedef struct { uint32_t signature; // "PCMP" uint16_t length; @@ -59,21 +58,12 @@ typedef struct { uint32_t reserved[2]; } mp_processor_entry_t; - typedef struct { uint8_t type; // has value MP_BUS uint8_t busid; char bustype[6]; } mp_bus_entry_t; -#define BUSTYPE_EISA "EISA" -#define BUSTYPE_ISA "ISA" -#define BUSTYPE_INTERN "INTERN" -#define BUSTYPE_MCA "MCA" -#define BUSTYPE_VL "VL" -#define BUSTYPE_PCI "PCI" -#define BUSTYPE_PCMCIA "PCMCIA" - /* We don't understand the others */ typedef struct { @@ -117,6 +107,39 @@ typedef struct { uint8_t destapiclint; } mp_local_interrupt_entry_t; +#define RSDPSignature ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24)) +typedef struct { + char signature[8]; // "RSD " + uint8_t checksum; + char oemid[6]; + uint8_t revision; + uint32_t rsdt; + uint32_t length; + uint32_t xrsdt[2]; + uint8_t xsum; +} rsdp_t; + +#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24)) +#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24)) +typedef struct { + char signature[4]; // "RSDT" + uint32_t length; + uint8_t revision; + uint8_t checksum; + char oemid[18]; + char cid[4]; + char cver[4]; +} rsdt_t; + +#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24)) +typedef struct { + uint8_t type; + uint8_t length; + uint8_t acpi_id; + uint8_t apic_id; /* Local APIC number */ + uint32_t enabled; +} madt_processor_entry_t; + /* APIC definitions */ /* * APIC registers @@ -169,7 +192,6 @@ typedef uint32_t apic_register_t[4]; extern volatile apic_register_t *APIC; -unsigned smp_num_cpus(); unsigned smp_my_cpu_num(); void smp_init_bsp(void); @@ -178,6 +200,30 @@ void smp_init_aps(void); void smp_boot_ap(unsigned cpu_num); void smp_ap_booted(unsigned cpu_num); +typedef struct { + unsigned int slock; +} spinlock_t; + +struct barrier_s +{ + spinlock_t mutex; + spinlock_t lck; + int maxproc; + volatile int count; + spinlock_t st1; + spinlock_t st2; + spinlock_t s_lck; + int s_maxproc; + volatile int s_count; + spinlock_t s_st1; + spinlock_t s_st2; +}; + +void barrier(); +void s_barrier(); +void barrier_init(int max); +void s_barrier_init(int max); + static inline void __GET_CPUID(int ax, uint32_t *regs) { @@ -239,24 +285,79 @@ static inline uint64_t __GET_MSR(int cx) } while (0) #define OUTB(port, val) __GCC_OUT(b, b, port, val) -typedef struct { - unsigned int slock; -} spinlock_t; +static inline void spin_wait(spinlock_t *lck) +{ + if (cpu_id.fid.bits.mon) { + /* Use monitor/mwait for a low power, low contention spin */ + asm volatile( + "movl $0,%%ecx\n\t" + "movl %%ecx, %%edx\n\t" + "1:\n\t" + "movl %%edi,%%eax\n\t" + "monitor\n\t" + "cmpb $0,(%%edi)\n\t" + "jne 2f\n\t" + "movl %%ecx, %%eax\n\t" + "mwait\n\t" + "jmp 1b\n" + "2:" + : : "D" (lck): "%eax", "%ecx", "%edx" + ); + } else { + /* No monitor/mwait so just spin with a lot of nop's */ + int inc = 0x400; + asm volatile( + "1:\t" + "cmpb $0,%1\n\t" + "jne 2f\n\t" + "rep ; nop\n\t" + "jmp 1b\n" + "2:" + : : "c" (inc), "m" (lck->slock): "memory" + ); + } +} -static inline void spin_lock(volatile spinlock_t *lock) +static inline void spin_lock(spinlock_t *lck) { - asm volatile("\n1:\t" - " ; lock;decb %0\n\t" - "jns 3f\n" - "2:\t" - "rep;nop\n\t" - "cmpb $0,%0\n\t" - "jle 2b\n\t" - "jmp 1b\n" - "3:\n\t" - : "+m" (lock->slock) : : "memory"); + if (cpu_id.fid.bits.mon) { + /* Use monitor/mwait for a low power, low contention spin */ + asm volatile( + "\n1:\t" + " ; lock;decb (%%edi)\n\t" + "jns 3f\n" + "movl $0,%%ecx\n\t" + "movl %%ecx, %%edx\n\t" + "2:\t" + "movl %%edi,%%eax\n\t" + "monitor\n\t" + "movl %%ecx, %%eax\n\t" + "mwait\n\t" + "cmpb $0,(%%edi)\n\t" + "jle 2b\n\t" + "jmp 1b\n" + "3:\n\t" + : : "D" (lck): "%eax", "%ecx", "%edx" + ); + } else { + /* No monitor/mwait so just spin with a lot of nop's */ + int inc = 0x400; + asm volatile( + "\n1:\t" + " ; lock;decb %0\n\t" + "jns 3f\n" + "2:\t" + "rep;nop\n\t" + "cmpb $0,%0\n\t" + "jle 2b\n\t" + "jmp 1b\n" + "3:\n\t" + : "+m" (lck->slock) : "c" (inc) : "memory" + ); + } } -static inline void spin_unlock(volatile spinlock_t *lock) + +static inline void spin_unlock(spinlock_t *lock) { asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory"); } @@ -1,9 +1,5 @@ -/* Memtest86 SPD extension
- * added by Reto Sonderegger, 2004, reto@swissbit.com
- *
- * Released under version 2 of the Gnu Puclic License
- * ----------------------------------------------------
- * MemTest86+ V4.20 Specific code (GPL V2.0)
+/*
+ * MemTest86+ V5 Specific code (GPL V2.0)
* By Samuel DEMEULEMEESTER, sdemeule@memtest.org
* http://www.canardpc.com - http://www.memtest.org
*/
@@ -29,7 +25,7 @@ extern void wait_keyup(); int smbdev, smbfun;
unsigned short smbusbase;
-unsigned char spd[256];
+unsigned char spd_raw[256];
char s[] = {'/', 0, '-', 0, '\\', 0, '|', 0};
static void ich5_get_smb(void)
@@ -40,6 +36,40 @@ static void ich5_get_smb(void) if (result == 0) smbusbase = (unsigned short) x & 0xFFFE;
}
+static void piix4_get_smb(void)
+{
+ unsigned long x;
+ int result;
+
+ result = pci_conf_read(0, smbdev, smbfun, 0x08, 1, &x);
+
+ if(x < 0x40){
+ // SB600/700
+ result = pci_conf_read(0, smbdev, smbfun, 0x90, 2, &x);
+ if (result == 0) smbusbase = (unsigned short) x & 0xFFFE;
+ } else {
+ // SB800
+ sb800_get_smb();
+ }
+}
+
+void sb800_get_smb(void)
+{
+ int lbyte, hbyte;
+
+ __outb(AMD_SMBUS_BASE_REG + 1, AMD_INDEX_IO_PORT);
+ lbyte = __inb(AMD_DATA_IO_PORT);
+ __outb(AMD_SMBUS_BASE_REG, AMD_INDEX_IO_PORT);
+ hbyte = __inb(AMD_DATA_IO_PORT);
+
+ smbusbase = lbyte;
+ smbusbase <<= 8;
+ smbusbase += hbyte;
+ smbusbase &= 0xFFE0;
+
+ if (smbusbase == 0xFFE0) { smbusbase = 0; }
+}
+
unsigned char ich5_smb_read_byte(unsigned char adr, unsigned char cmd)
{
int l1, h1, l2, h2;
@@ -53,9 +83,9 @@ unsigned char ich5_smb_read_byte(unsigned char adr, unsigned char cmd) rdtsc(l1, h1);
//cprint(POP2_Y, POP2_X + 16, s + cmd % 8); // progress bar
while (!(__inb(SMBHSTSTS) & 0x02)) { // wait til command finished
- rdtsc(l2, h2);
- t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / v->clks_msec;
- if (t > 10) break; // break after 10ms
+ rdtsc(l2, h2);
+ t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / v->clks_msec;
+ if (t > 10) break; // break after 10ms
}
return __inb(SMBHSTDAT);
}
@@ -63,10 +93,10 @@ unsigned char ich5_smb_read_byte(unsigned char adr, unsigned char cmd) static int ich5_read_spd(int dimmadr)
{
int x;
- spd[0] = ich5_smb_read_byte(0x50 + dimmadr, 0);
- if (spd[0] == 0xff) return -1; // no spd here
+ spd_raw[0] = ich5_smb_read_byte(0x50 + dimmadr, 0);
+ if (spd_raw[0] == 0xff) return -1; // no spd here
for (x = 1; x < 256; x++) {
- spd[x] = ich5_smb_read_byte(0x50 + dimmadr, (unsigned char) x);
+ spd_raw[x] = ich5_smb_read_byte(0x50 + dimmadr, (unsigned char) x);
}
return 0;
}
@@ -106,10 +136,10 @@ unsigned char us15w_smb_read_byte(unsigned char adr, unsigned char cmd) static int us15w_read_spd(int dimmadr)
{
int x;
- spd[0] = us15w_smb_read_byte(0x50 + dimmadr, 0);
- if (spd[0] == 0xff) return -1; // no spd here
+ spd_raw[0] = us15w_smb_read_byte(0x50 + dimmadr, 0);
+ if (spd_raw[0] == 0xff) return -1; // no spd here
for (x = 1; x < 256; x++) {
- spd[x] = us15w_smb_read_byte(0x50 + dimmadr, (unsigned char) x);
+ spd_raw[x] = us15w_smb_read_byte(0x50 + dimmadr, (unsigned char) x);
}
return 0;
}
@@ -123,21 +153,29 @@ struct pci_smbus_controller { };
static struct pci_smbus_controller smbcontrollers[] = {
-{0x8086, 0x1C22, "Intel P67", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x3B30, "Intel P55", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x3A60, "Intel ICH10B", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x3A30, "Intel ICH10R", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x2930, "Intel ICH9", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x283E, "Intel ICH8", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x27DA, "Intel ICH7", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x266A, "Intel ICH6", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x24D3, "Intel ICH5", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x24C3, "Intel ICH4", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x25A4, "Intel 6300ESB", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x269B, "Intel ESB2", ich5_get_smb, ich5_read_spd},
-{0x8086, 0x8119, "Intel US15W", us15w_get_smb, us15w_read_spd},
-{0x8086, 0x5032, "Intel EP80579", ich5_get_smb, ich5_read_spd},
-{0, 0, "", NULL, NULL}
+ // Intel SMBUS
+ {0x8086, 0x9C22, "Intel HSW-ULT", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x8C22, "Intel HSW", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x1E22, "Intel Z77", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x1C22, "Intel P67", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x3B30, "Intel P55", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x3A60, "Intel ICH10B", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x3A30, "Intel ICH10R", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x2930, "Intel ICH9", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x283E, "Intel ICH8", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x27DA, "Intel ICH7", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x266A, "Intel ICH6", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x24D3, "Intel ICH5", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x24C3, "Intel ICH4", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x25A4, "Intel 6300ESB", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x269B, "Intel ESB2", ich5_get_smb, ich5_read_spd},
+ {0x8086, 0x8119, "Intel US15W", us15w_get_smb, us15w_read_spd},
+ {0x8086, 0x5032, "Intel EP80579", ich5_get_smb, ich5_read_spd},
+
+ // AMD SMBUS
+ {0x1002, 0x4385, "AMD SB600/700", piix4_get_smb, ich5_read_spd},
+ {0x1022, 0x780B, "AMD SB800/900", sb800_get_smb, ich5_read_spd},
+ {0, 0, "", NULL, NULL}
};
@@ -145,6 +183,7 @@ int find_smb_controller(void) {
int i = 0;
unsigned long valuev, valued;
+
for (smbdev = 0; smbdev < 32; smbdev++) {
for (smbfun = 0; smbfun < 8; smbfun++) {
pci_conf_read(0, smbdev, smbfun, 0, 2, &valuev);
@@ -173,6 +212,7 @@ void get_spd_spec(void) int module_size;
int curcol;
int temp_nbd;
+ int tck;
index = find_smb_controller();
@@ -184,59 +224,75 @@ void get_spd_spec(void) smbcontrollers[index].get_adr();
cprint(LINE_SPD-2, 0, "Memory SPD Informations");
- cprint(LINE_SPD-1, 0, "-----------------------------------");
+ cprint(LINE_SPD-1, 0, "--------------------------");
for (j = 0; j < 8; j++) {
if (smbcontrollers[index].read_spd(j) == 0) {
curcol = 1;
- if(spd[2] == 0x0b){
+ if(spd_raw[2] == 0x0b){
// We are here if DDR3 present
// First print slot#, module capacity
cprint(LINE_SPD+k, curcol, " - Slot :");
dprint(LINE_SPD+k, curcol+8, k, 1, 0);
- module_size = get_ddr3_module_size(spd[4] & 0xF, spd[8] & 0x7, spd[7] & 0x7, spd[7] >> 3);
+ module_size = get_ddr3_module_size(spd_raw[4] & 0xF, spd_raw[8] & 0x7, spd_raw[7] & 0x7, spd_raw[7] >> 3);
temp_nbd = getnum(module_size); curcol += 12;
dprint(LINE_SPD+k, curcol, module_size, temp_nbd, 0); curcol += temp_nbd;
cprint(LINE_SPD+k, curcol, " MB"); curcol += 4;
+ // If XMP is supported, check Tck in XMP reg
+ if(spd_raw[176] == 0x0C && spd_raw[177] == 0x4A && spd_raw[12])
+ {
+ tck = spd_raw[186];
+ } else {
+ tck = spd_raw[12];
+ }
+
// Then module jedec speed
- switch(spd[12])
+ switch(tck)
{
default:
+ cprint(LINE_SPD+k, curcol, "DDR3-????");
+ break;
case 20:
- cprint(LINE_SPD+k, curcol, "PC3-6400");
- curcol += 8;
+ cprint(LINE_SPD+k, curcol, "DDR3-800");
+ curcol--;
break;
case 15:
- cprint(LINE_SPD+k, curcol, "PC3-8500");
- curcol += 8;
+ cprint(LINE_SPD+k, curcol, "DDR3-1066");
break;
case 12:
- cprint(LINE_SPD+k, curcol, "PC3-10600");
- curcol += 9;
+ cprint(LINE_SPD+k, curcol, "DDR3-1333");
break;
case 10:
- cprint(LINE_SPD+k, curcol, "PC3-12800");
- curcol += 9;
+ cprint(LINE_SPD+k, curcol, "DDR3-1600");
+ break;
+ case 9:
+ cprint(LINE_SPD+k, curcol, "DDR3-1866");
break;
case 8:
- cprint(LINE_SPD+k, curcol, "PC3-15000");
- curcol += 9;
+ cprint(LINE_SPD+k, curcol, "DDR3-2133");
+ break;
+ case 7:
+ cprint(LINE_SPD+k, curcol, "DDR3-2400");
break;
case 6:
- cprint(LINE_SPD+k, curcol, "PC3-16000");
- curcol += 9;
+ cprint(LINE_SPD+k, curcol, "DDR3-2533");
+ break;
+ case 5:
+ cprint(LINE_SPD+k, curcol, "DDR3-2666");
break;
}
- curcol++;
+ curcol += 10;
+
+ if((spd_raw[8] >> 3) == 1) { cprint(LINE_SPD+k, curcol, "ECC"); curcol += 4; }
// Then print module infos (manufacturer & part number)
- spd[117] &= 0x0F; // Parity odd or even
+ spd_raw[117] &= 0x0F; // Parity odd or even
for (i = 0; jep106[i].cont_code < 9; i++) {
- if (spd[117] == jep106[i].cont_code && spd[118] == jep106[i].hex_byte) {
+ if (spd_raw[117] == jep106[i].cont_code && spd_raw[118] == jep106[i].hex_byte) {
// We are here if a Jedec manufacturer is detected
cprint(LINE_SPD+k, curcol, "-"); curcol += 2;
cprint(LINE_SPD+k, curcol, jep106[i].name);
@@ -244,12 +300,25 @@ void get_spd_spec(void) curcol++;
// Display module serial number
for (h = 128; h < 146; h++) {
- cprint(16+k, curcol, convert_hex_to_char(spd[h]));
+ cprint(LINE_SPD+k, curcol, convert_hex_to_char(spd_raw[h]));
curcol++;
}
+
+ // Detect Week and Year of Manufacturing (Think to upgrade after 2015 !!!)
+ if(curcol <= 72 && spd_raw[120] > 3 && spd_raw[120] < 16 && spd_raw[121] < 55)
+ {
+ cprint(LINE_SPD+k, curcol, "(W");
+ dprint(LINE_SPD+k, curcol+2, spd_raw[121], 2, 0);
+ if(spd_raw[121] < 10) { cprint(LINE_SPD+k, curcol+2, "0"); }
+ cprint(LINE_SPD+k, curcol+4, "'");
+ dprint(LINE_SPD+k, curcol+5, spd_raw[120], 2, 0);
+ if(spd_raw[120] < 10) { cprint(LINE_SPD+k, curcol+5, "0"); }
+ cprint(LINE_SPD+k, curcol+7, ")");
+ curcol += 9;
+ }
// Detect XMP Memory
- if(spd[176] == 0x0C && spd[177] == 0x4A)
+ if(spd_raw[176] == 0x0C && spd_raw[177] == 0x4A)
{
cprint(LINE_SPD+k, curcol, "*XMP*");
}
@@ -257,12 +326,12 @@ void get_spd_spec(void) }
}
// We enter this function if DDR2 is detected
- if(spd[2] == 0x08){
+ if(spd_raw[2] == 0x08){
// First print slot#, module capacity
cprint(LINE_SPD+k, curcol, " - Slot :");
dprint(LINE_SPD+k, curcol+8, k, 1, 0);
- module_size = get_ddr2_module_size(spd[31], spd[5]);
+ module_size = get_ddr2_module_size(spd_raw[31], spd_raw[5]);
temp_nbd = getnum(module_size); curcol += 12;
dprint(LINE_SPD+k, curcol, module_size, temp_nbd, 0); curcol += temp_nbd;
cprint(LINE_SPD+k, curcol, " MB"); curcol += 4;
@@ -270,27 +339,29 @@ void get_spd_spec(void) // Then module jedec speed
float ddr2_speed, byte1, byte2;
- byte1 = (spd[9] >> 4) * 10;
- byte2 = spd[9] & 0xF;
+ byte1 = (spd_raw[9] >> 4) * 10;
+ byte2 = spd_raw[9] & 0xF;
- ddr2_speed = 1 / (byte1 + byte2) * 10000;
+ ddr2_speed = 1 / (byte1 + byte2) * 10000 * 2;
temp_nbd = getnum(ddr2_speed);
cprint(LINE_SPD+k, curcol, "DDR2-"); curcol += 5;
dprint(LINE_SPD+k, curcol, ddr2_speed, temp_nbd, 0); curcol += temp_nbd;
+
+ if((spd_raw[11] >> 1) == 1) { cprint(LINE_SPD+k, curcol+1, "ECC"); curcol += 4; }
// Then print module infos (manufacturer & part number)
int ccode = 0;
for(i = 64; i < 72; i++)
{
- if(spd[i] == 0x7F) { ccode++; }
+ if(spd_raw[i] == 0x7F) { ccode++; }
}
curcol++;
for (i = 0; jep106[i].cont_code < 9; i++) {
- if (ccode == jep106[i].cont_code && spd[64+ccode] == jep106[i].hex_byte) {
+ if (ccode == jep106[i].cont_code && spd_raw[64+ccode] == jep106[i].hex_byte) {
// We are here if a Jedec manufacturer is detected
cprint(LINE_SPD+k, curcol, "-"); curcol += 2;
cprint(LINE_SPD+k, curcol, jep106[i].name);
@@ -298,7 +369,7 @@ void get_spd_spec(void) curcol++;
// Display module serial number
for (h = 73; h < 91; h++) {
- cprint(16+k, curcol, convert_hex_to_char(spd[h]));
+ cprint(LINE_SPD+k, curcol, convert_hex_to_char(spd_raw[h]));
curcol++;
}
@@ -333,7 +404,7 @@ void show_spd(void) if (smbcontrollers[index].read_spd(j) == 0) {
dprint(POP2_Y, POP2_X + 15, j, 2, 0);
for (i = 0; i < 256; i++) {
- hprint2(2 + POP2_Y + i / 16, 3 + POP2_X + (i % 16) * 3, spd[i], 2);
+ hprint2(2 + POP2_Y + i / 16, 3 + POP2_X + (i % 16) * 3, spd_raw[i], 2);
}
flag = 0;
while(!flag) {
@@ -1,13 +1,17 @@ /* - * MemTest86+ V3.00 Specific code (GPL V2.0) + * MemTest86+ V5.00 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.canardpc.com - http://www.memtest.org */ + +#define AMD_INDEX_IO_PORT 0xCD6 +#define AMD_DATA_IO_PORT 0xCD7 +#define AMD_SMBUS_BASE_REG 0x2C void get_spd_spec(void); int get_ddr2_module_size(int rank_density_byte, int rank_num_byte); int get_ddr3_module_size(int sdram_capacity, int prim_bus_width, int sdram_width, int ranks); char* convert_hex_to_char(unsigned hex_org); -#define LINE_SPD 16 +void sb800_get_smb(void); diff --git a/stddef.h b/stddef.h new file mode 100644 index 0000000..213c89b --- /dev/null +++ b/stddef.h @@ -0,0 +1,8 @@ +#ifndef I386_STDDEF_H +#define I386_STDDEF_H + +#define NULL ((void *)0) + +typedef unsigned long size_t; + +#endif /* I386_STDDEF_H */ @@ -0,0 +1,52 @@ +#ifndef I386_STDINT_H +#define I386_STDINT_H + +/* Exact integral types */ +typedef unsigned char uint8_t; +typedef signed char int8_t; + +typedef unsigned short uint16_t; +typedef signed short int16_t; + +typedef unsigned int uint32_t; +typedef signed int int32_t; + +typedef unsigned long long uint64_t; +typedef signed long long int64_t; + +/* Small types */ +typedef unsigned char uint_least8_t; +typedef signed char int_least8_t; + +typedef unsigned short uint_least16_t; +typedef signed short int_least16_t; + +typedef unsigned int uint_least32_t; +typedef signed int int_least32_t; + +typedef unsigned long long uint_least64_t; +typedef signed long long int_least64_t; + +/* Fast Types */ +typedef unsigned char uint_fast8_t; +typedef signed char int_fast8_t; + +typedef unsigned int uint_fast16_t; +typedef signed int int_fast16_t; + +typedef unsigned int uint_fast32_t; +typedef signed int int_fast32_t; + +typedef unsigned long long uint_fast64_t; +typedef signed long long int_fast64_t; + +/* Types for `void *' pointers. */ +typedef int intptr_t; +typedef unsigned int uintptr_t; + +/* Largest integral types */ +typedef long long int intmax_t; +typedef unsigned long long uintmax_t; + + +#endif /* I386_STDINT_H */
\ No newline at end of file @@ -1,53 +1,94 @@ - -/* test.c - MemTest-86 Version 3.2 +/* test.c - MemTest-86 Version 3.4 * * Released under version 2 of the Gnu Public License. - * By Chris Brady, cbrady@sgi.com + * By Chris Brady * ---------------------------------------------------- - * MemTest86+ V3.00 Specific code (GPL V2.0) + * MemTest86+ V5 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.canardpc.com - http://www.memtest.org + * Thanks to Passmark for calculate_chunk() and various comments ! */ - + #include "test.h" #include "config.h" +#include "stdint.h" +#include "cpuid.h" +#include "smp.h" #include <sys/io.h> -#include "dmi.h" -#include <inttypes.h> -extern int segs, bail; -extern volatile ulong *p; -extern ulong p1, p2; +extern struct cpu_ident cpu_id; +extern volatile int mstr_cpu; +extern volatile int run_cpus; +extern volatile int test; +extern volatile int segs, bail; extern int test_ticks, nticks; extern struct tseq tseq[]; extern void update_err_counts(void); extern void print_err_counts(void); +void rand_seed( unsigned int seed1, unsigned int seed2, int me); +ulong rand(int me); void poll_errors(); -int ecount = 0; - static inline ulong roundup(ulong value, ulong mask) { return (value + mask) & ~mask; } + +// start / end - return values for range to test +// me - this threads CPU number +// j - index into v->map for current segment we are testing +// align - number of bytes to align each block to +void calculate_chunk(ulong** start, ulong** end, int me, int j, int makeMultipleOf) +{ + ulong chunk; + + + // If we are only running 1 CPU then test the whole block + if (run_cpus == 1) { + *start = v->map[j].start; + *end = v->map[j].end; + } + else{ + + // Divide the current segment by the number of CPUs + chunk = (ulong)v->map[j].end-(ulong)v->map[j].start; + chunk /= run_cpus; + + // Round down to the nearest desired bitlength multiple + chunk = (chunk + (makeMultipleOf-1)) & ~(makeMultipleOf-1); + + // Figure out chunk boundaries + *start = (ulong*)((ulong)v->map[j].start+(chunk*me)); + /* Set end addrs for the highest CPU num to the + * end of the segment for rounding errors */ + // Also rounds down to boundary if needed, may miss some ram but better than crashing or producing false errors. + // This rounding probably will never happen as the segments should be in 4096 bytes pages if I understand correctly. + if (me == mstr_cpu) { + *end = (ulong*)(v->map[j].end); + } else { + *end = (ulong*)((ulong)(*start) + chunk); + (*end)--; + } + } +} + /* * Memory address test, walking ones */ -void addr_tst1() +void addr_tst1(int me) { int i, j, k; - volatile ulong *pt; - volatile ulong *end; - ulong bad, mask, bank; + volatile ulong *p, *pt, *end; + ulong bad, mask, bank, p1; /* Test the global address bits */ for (p1=0, j=0; j<2; j++) { - hprint(LINE_PAT, COL_PAT, p1); + hprint(LINE_PAT, COL_PAT, p1); /* Set pattern in our lowest multiple of 0x20000 */ p = (ulong *)roundup((ulong)v->map[0].start, 0x1ffff); *p = p1; - + /* Now write pattern compliment */ p1 = ~p1; end = v->map[segs-1].end; @@ -55,23 +96,23 @@ void addr_tst1() mask = 4; do { pt = (ulong *)((ulong)p | mask); - if ((uintptr_t)pt == (uintptr_t)p) { + if (pt == p) { mask = mask << 1; continue; } - if ((uintptr_t)pt >= (uintptr_t)end) { + if (pt >= end) { break; } *pt = p1; - if ((uintptr_t)(bad = *p) != (uintptr_t)~p1) { + if ((bad = *p) != ~p1) { ad_err1((ulong *)p, (ulong *)mask, - bad, ~p1); + bad, ~p1); i = 1000; } mask = mask << 1; } while(mask); } - do_tick(); + do_tick(me); BAILR } @@ -84,48 +125,49 @@ void addr_tst1() bank = 0x40000; } for (p1=0, k=0; k<2; k++) { - hprint(LINE_PAT, COL_PAT, p1); + hprint(LINE_PAT, COL_PAT, p1); for (j=0; j<segs; j++) { p = v->map[j].start; /* Force start address to be a multiple of 256k */ p = (ulong *)roundup((ulong)p, bank - 1); end = v->map[j].end; - while ((uintptr_t)p < (uintptr_t)end) { + /* Redundant checks for overflow */ + while (p < end && p > v->map[j].start && p != 0) { *p = p1; p1 = ~p1; - for (i=0; i<200; i++) { + for (i=0; i<50; i++) { mask = 4; do { pt = (ulong *) ((ulong)p | mask); - if ((uintptr_t)pt == (uintptr_t)p) { + if (pt == p) { mask = mask << 1; continue; } - if ((uintptr_t)pt >= (uintptr_t)end) { + if (pt >= end) { break; } *pt = p1; - if ((uintptr_t)(bad = *p) != (uintptr_t)~p1) { + if ((bad = *p) != ~p1) { ad_err1((ulong *)p, - (ulong *)mask, - bad,~p1); + (ulong *)mask, + bad,~p1); i = 200; } mask = mask << 1; } while(mask); } - if ((uintptr_t)(p + bank/4) > (uintptr_t)p) { - p += bank/4; + if (p + bank > p) { + p += bank; } else { p = end; } p1 = ~p1; } } - do_tick(); + do_tick(me); BAILR p1 = ~p1; } @@ -134,13 +176,12 @@ void addr_tst1() /* * Memory address test, own address */ -void addr_tst2() +void addr_tst2(int me) { int j, done; - volatile ulong *pe; - volatile ulong *end, *start; + ulong *p, *pe, *end, *start; - cprint(LINE_PAT, COL_PAT, " "); + cprint(LINE_PAT, COL_PAT, "address "); /* Write each address with it's own address */ for (j=0; j<segs; j++) { @@ -150,39 +191,40 @@ void addr_tst2() p = start; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code - * for (; p < pe; p++) { + * for (; p <= pe; p++) { * *p = (ulong)p; * } */ asm __volatile__ ( - "jmp L90\n\t" - + "jmp L91\n\t" ".p2align 4,,7\n\t" "L90:\n\t" - "movl %%edi,(%%edi)\n\t" "addl $4,%%edi\n\t" + "L91:\n\t" + "movl %%edi,(%%edi)\n\t" "cmpl %%edx,%%edi\n\t" "jb L90\n\t" - : "=D" (p) - : "D" (p), "d" (pe) + : : "D" (p), "d" (pe) ); - do_tick(); - BAILR + p = pe + 1; } while (!done); } @@ -194,41 +236,44 @@ void addr_tst2() p = start; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { - pe += SPINSZ; - } else { - pe = end; - } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe + SPINSZ > pe && pe != 0) { + pe += SPINSZ; + } else { + pe = end; + } + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe ) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code - * for (; p < pe; p++) { + * for (; p <= pe; p++) { * if((bad = *p) != (ulong)p) { * ad_err2((ulong)p, bad); * } * } */ asm __volatile__ ( - "jmp L91\n\t" - + "jmp L95\n\t" ".p2align 4,,7\n\t" - "L91:\n\t" + "L99:\n\t" + "addl $4,%%edi\n\t" + "L95:\n\t" "movl (%%edi),%%ecx\n\t" "cmpl %%edi,%%ecx\n\t" - "jne L93\n\t" - "L92:\n\t" - "addl $4,%%edi\n\t" + "jne L97\n\t" + "L96:\n\t" "cmpl %%edx,%%edi\n\t" - "jb L91\n\t" - "jmp L94\n\t" - - "L93:\n\t" + "jb L99\n\t" + "jmp L98\n\t" + + "L97:\n\t" "pushl %%edx\n\t" "pushl %%ecx\n\t" "pushl %%edi\n\t" @@ -236,15 +281,13 @@ void addr_tst2() "popl %%edi\n\t" "popl %%ecx\n\t" "popl %%edx\n\t" - "jmp L92\n\t" + "jmp L96\n\t" - "L94:\n\t" - : "=D" (p) - : "D" (p), "d" (pe) + "L98:\n\t" + : : "D" (p), "d" (pe) : "ecx" ); - do_tick(); - BAILR + p = pe + 1; } while (!done); } } @@ -255,16 +298,17 @@ void addr_tst2() * produce random numbers in reverse order testing is only done in the forward * direction. */ -void movinvr() +void movinvr(int me) { int i, j, done, seed1, seed2; - volatile ulong *pe; - volatile ulong *start,*end; - ulong num; - uintptr_t seg_start; + ulong *p; + ulong *pe; + ulong *start,*end; + ulong xorVal; + //ulong num, bad; /* Initialize memory with initial sequence of random numbers. */ - if (v->rdtsc) { + if (cpu_id.fid.bits.rdtsc) { asm __volatile__ ("rdtsc":"=a" (seed1),"=d" (seed2)); } else { seed1 = 521288629 + v->pass; @@ -272,85 +316,87 @@ void movinvr() } /* Display the current seed */ - hprint(LINE_PAT, COL_PAT, seed1); - rand_seed(seed1, seed2); + if (mstr_cpu == me) hprint(LINE_PAT, COL_PAT, seed1); + rand_seed(seed1, seed2, me); for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 4); pe = start; p = start; - seg_start = (uintptr_t)p; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if (seg_start == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code */ /* - for (; p < pe; p++) { - *p = rand(); + for (; p <= pe; p++) { + *p = rand(me); } */ - asm __volatile__ ( - "jmp L200\n\t" - ".p2align 4,,7\n\t" - "L200:\n\t" - "call rand\n\t" + asm __volatile__ ( + "jmp L200\n\t" + ".p2align 4,,7\n\t" + "L201:\n\t" + "addl $4,%%edi\n\t" + "L200:\n\t" + "pushl %%ecx\n\t" \ + "call rand\n\t" + "popl %%ecx\n\t" \ "movl %%eax,(%%edi)\n\t" - "addl $4,%%edi\n\t" - "cmpl %%ebx,%%edi\n\t" - "jb L200\n\t" - : "=D" (p) - : "D" (p), "b" (pe) - : "eax", "edx" - ); - - do_tick(); - BAILR + "cmpl %%ebx,%%edi\n\t" + "jb L201\n\t" + : : "D" (p), "b" (pe), "c" (me) + : "eax" + ); + p = pe + 1; } while (!done); } /* Do moving inversions test. Check for initial pattern and then - * write the complement for each memory location. Test from bottom - * up and then from the top down. */ + * write the complement for each memory location. + */ for (i=0; i<2; i++) { - rand_seed(seed1, seed2); + rand_seed(seed1, seed2, me); for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 4); pe = start; p = start; - seg_start = (uintptr_t)p; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if (seg_start == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code */ -/* - for (; p < pe; p++) { - num = rand(); + + /*for (; p <= pe; p++) { + num = rand(me); if (i) { num = ~num; } @@ -358,51 +404,85 @@ void movinvr() error((ulong*)p, num, bad); } *p = ~num; - } -*/ + }*/ + if (i) { - num = 0xffffffff; + xorVal = 0xffffffff; } else { - num = 0; + xorVal = 0; } asm __volatile__ ( - "jmp L26\n\t" \ + + "pushl %%ebp\n\t" - ".p2align 4,,7\n\t" \ - "L26:\n\t" \ + // Skip first increment + "jmp L26\n\t" + ".p2align 4,,7\n\t" + + // increment 4 bytes (32-bits) + "L27:\n\t" + "addl $4,%%edi\n\t" + + // Check this byte + "L26:\n\t" + + // Get next random number, pass in me(edx), random value returned in num(eax) + // num = rand(me); + // cdecl call maintains all registers except eax, ecx, and edx + // We maintain edx with a push and pop here using it also as an input + // we don't need the current eax value and want it to change to the return value + // we overwrite ecx shortly after this discarding its current value + "pushl %%edx\n\t" // Push function inputs onto stack "call rand\n\t" - "xorl %%ebx,%%eax\n\t" \ - "movl (%%edi),%%ecx\n\t" \ - "cmpl %%eax,%%ecx\n\t" \ - "jne L23\n\t" \ - "L25:\n\t" \ - "movl $0xffffffff,%%edx\n\t" \ - "xorl %%edx,%%eax\n\t" \ - "movl %%eax,(%%edi)\n\t" \ - "addl $4,%%edi\n\t" \ - "cmpl %%esi,%%edi\n\t" \ - "jb L26\n\t" \ - "jmp L24\n" \ + "popl %%edx\n\t" // Remove function inputs from stack - "L23:\n\t" \ - "pushl %%esi\n\t" \ - "pushl %%ecx\n\t" \ - "pushl %%eax\n\t" \ - "pushl %%edi\n\t" \ - "call error\n\t" \ - "popl %%edi\n\t" \ - "popl %%eax\n\t" \ - "popl %%ecx\n\t" \ - "popl %%esi\n\t" \ - "jmp L25\n" \ + // XOR the random number with xorVal(ebx), which is either 0xffffffff or 0 depending on the outer loop + // if (i) { num = ~num; } + "xorl %%ebx,%%eax\n\t" + + // Move the current value of the current position p(edi) into bad(ecx) + // (bad=*p) + "movl (%%edi),%%ecx\n\t" + + // Compare bad(ecx) to num(eax) + "cmpl %%eax,%%ecx\n\t" - "L24:\n\t" \ - : "=D" (p) - : "D" (p), "S" (pe), "b" (num) - : "eax", "ecx", "edx" + // If not equal jump the error case + "jne L23\n\t" + + // Set a new value or not num(eax) at the current position p(edi) + // *p = ~num; + "L25:\n\t" + "movl $0xffffffff,%%ebp\n\t" + "xorl %%ebp,%%eax\n\t" + "movl %%eax,(%%edi)\n\t" + + // Loop until current position p(edi) equals the end position pe(esi) + "cmpl %%esi,%%edi\n\t" + "jb L27\n\t" + "jmp L24\n" + + // Error case + "L23:\n\t" + // Must manually maintain eax, ecx, and edx as part of cdecl call convention + "pushl %%edx\n\t" + "pushl %%ecx\n\t" // Next three pushes are functions input + "pushl %%eax\n\t" + "pushl %%edi\n\t" + "call error\n\t" + "popl %%edi\n\t" // Remove function inputs from stack and restore register values + "popl %%eax\n\t" + "popl %%ecx\n\t" + "popl %%edx\n\t" + "jmp L25\n" + + "L24:\n\t" + "popl %%ebp\n\t" + :: "D" (p), "S" (pe), "b" (xorVal), + "d" (me) + : "eax", "ecx" ); - do_tick(); - BAILR + p = pe + 1; } while (!done); } } @@ -412,51 +492,54 @@ void movinvr() * Test all of memory using a "moving inversions" algorithm using the * pattern in p1 and it's complement in p2. */ -void movinv1(int iter, ulong p1, ulong p2) +void movinv1 (int iter, ulong p1, ulong p2, int me) { int i, j, done; - volatile ulong *pe; - volatile ulong len; - volatile ulong *start,*end; + ulong *p, *pe, len, *start, *end; /* Display the current pattern */ - hprint(LINE_PAT, COL_PAT, p1); + if (mstr_cpu == me) hprint(LINE_PAT, COL_PAT, p1); /* Initialize memory with the initial pattern. */ for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 4); + + pe = start; p = start; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - len = pe - p; - if ((uintptr_t)p == (uintptr_t)pe) { + len = pe - p + 1; + if (p == pe ) { break; } -/* Original C code replaced with hand tuned assembly code - * for (; p < pe; p++) { - * *p = p1; - * } - */ + + //Original C code replaced with hand tuned assembly code + // seems broken + /*for (; p <= pe; p++) { + *p = p1; + }*/ + asm __volatile__ ( "rep\n\t" \ "stosl\n\t" - : "=D" (p) - : "c" (len), "0" (p), "a" (p1) + : : "c" (len), "D" (p), "a" (p1) ); - do_tick(); - BAILR + + p = pe + 1; } while (!done); } @@ -465,46 +548,50 @@ void movinv1(int iter, ulong p1, ulong p2) * up and then from the top down. */ for (i=0; i<iter; i++) { for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 4); pe = start; p = start; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } -/* Original C code replaced with hand tuned assembly code - * for (; p < pe; p++) { - * if ((bad=*p) != p1) { - * error((ulong*)p, p1, bad); - * } - * *p = p2; - * } - */ + + // Original C code replaced with hand tuned assembly code + // seems broken + /*for (; p <= pe; p++) { + if ((bad=*p) != p1) { + error((ulong*)p, p1, bad); + } + *p = p2; + }*/ + asm __volatile__ ( "jmp L2\n\t" \ - ".p2align 4,,7\n\t" \ + "L0:\n\t" \ + "addl $4,%%edi\n\t" \ "L2:\n\t" \ "movl (%%edi),%%ecx\n\t" \ "cmpl %%eax,%%ecx\n\t" \ "jne L3\n\t" \ "L5:\n\t" \ "movl %%ebx,(%%edi)\n\t" \ - "addl $4,%%edi\n\t" \ "cmpl %%edx,%%edi\n\t" \ - "jb L2\n\t" \ + "jb L0\n\t" \ "jmp L4\n" \ "L3:\n\t" \ @@ -522,57 +609,61 @@ void movinv1(int iter, ulong p1, ulong p2) "jmp L5\n" \ "L4:\n\t" \ - : "=D" (p) - : "a" (p1), "0" (p), "d" (pe), "b" (p2) + :: "a" (p1), "D" (p), "d" (pe), "b" (p2) : "ecx" ); - do_tick(); - BAILR + p = pe + 1; } while (!done); } for (j=segs-1; j>=0; j--) { - start = v->map[j].start; - end = v->map[j].end; - pe = end -1; - p = end -1; + calculate_chunk(&start, &end, me, j, 4); + pe = end; + p = end; done = 0; do { + do_tick(me); + BAILR + /* Check for underflow */ - if ((uintptr_t)(pe - SPINSZ) < (uintptr_t)pe) { + if (pe - SPINSZ < pe && pe != 0) { pe -= SPINSZ; } else { pe = start; + done++; } - if ((uintptr_t)pe <= (uintptr_t)start) { + + /* Since we are using unsigned addresses a + * redundent check is required */ + if (pe < start || pe > end) { pe = start; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } -/* Original C code replaced with hand tuned assembly code - * do { - * if ((bad=*p) != p2) { - * error((ulong*)p, p2, bad); - * } - * *p = p1; - * } while (p-- > pe); - */ + + //Original C code replaced with hand tuned assembly code + // seems broken + /*do { + if ((bad=*p) != p2) { + error((ulong*)p, p2, bad); + } + *p = p1; + } while (--p >= pe);*/ + asm __volatile__ ( - "addl $4, %%edi\n\t" "jmp L9\n\t" - ".p2align 4,,7\n\t" - "L9:\n\t" + "L11:\n\t" "subl $4, %%edi\n\t" + "L9:\n\t" "movl (%%edi),%%ecx\n\t" "cmpl %%ebx,%%ecx\n\t" "jne L6\n\t" "L10:\n\t" "movl %%eax,(%%edi)\n\t" "cmpl %%edi, %%edx\n\t" - "jne L9\n\t" - "subl $4, %%edi\n\t" + "jne L11\n\t" "jmp L7\n\t" "L6:\n\t" @@ -590,58 +681,52 @@ void movinv1(int iter, ulong p1, ulong p2) "jmp L10\n" "L7:\n\t" - : "=D" (p) - : "a" (p1), "0" (p), "d" (pe), "b" (p2) + :: "a" (p1), "D" (p), "d" (pe), "b" (p2) : "ecx" ); - do_tick(); - BAILR + p = pe - 1; } while (!done); } } } -void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off) +void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off,int me) { - int i, j, k=0, done; - volatile ulong *pe; - volatile ulong *start, *end; - ulong pat = 0; - -/* CDH start - * ulong p3 = sval << 31; - * CDH end - */ + int i, j, k=0, n=0, done; + ulong *p, *pe, *start, *end, pat = 0, p3; + p3 = sval << 31; /* Display the current pattern */ - hprint(LINE_PAT, COL_PAT, p1); + if (mstr_cpu == me) hprint(LINE_PAT, COL_PAT, p1); /* Initialize memory with the initial pattern. */ for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 64); pe = start; p = start; done = 0; k = off; pat = p1; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } /* Do a SPINSZ section of memory */ /* Original C code replaced with hand tuned assembly code - * while (p < pe) { + * while (p <= pe) { * *p = pat; * if (++k >= 32) { * pat = lb; @@ -654,24 +739,29 @@ void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off) * } */ asm __volatile__ ( - "jmp L20\n\t" - ".p2align 4,,7\n\t" - -/* CDH start */ - "L20:\n\t" - "movl %%ecx,(%%edi)\n\t" - "incb %%bl\n\t" - "addl $4,%%edi\n\t" - "roll $1,%%ecx\n\t" - "cmpl %%edx,%%edi\n\t" - "jb L20\n\t" - "andb $31,%%bl\n\t" - : "=b" (k), "=D" (p), "=c" (pat) - : "D" (p),"d" (pe),"b" (k),"c" (pat) -/* CDH end */ + "jmp L20\n\t" + ".p2align 4,,7\n\t" + "L923:\n\t" + "addl $4,%%edi\n\t" + "L20:\n\t" + "movl %%ecx,(%%edi)\n\t" + "addl $1,%%ebx\n\t" + "cmpl $32,%%ebx\n\t" + "jne L21\n\t" + "movl %%esi,%%ecx\n\t" + "xorl %%ebx,%%ebx\n\t" + "jmp L22\n" + "L21:\n\t" + "shll $1,%%ecx\n\t" + "orl %%eax,%%ecx\n\t" + "L22:\n\t" + "cmpl %%edx,%%edi\n\t" + "jb L923\n\t" + : "=b" (k), "=c" (pat) + : "D" (p),"d" (pe),"b" (k),"c" (pat), + "a" (sval), "S" (lb) ); - do_tick(); - BAILR + p = pe + 1; } while (!done); } @@ -680,33 +770,38 @@ void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off) * up and then from the top down. */ for (i=0; i<iter; i++) { for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 64); pe = start; p = start; done = 0; k = off; pat = p1; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code - * while (p < pe) { + * while (1) { * if ((bad=*p) != pat) { * error((ulong*)p, pat, bad); * } * *p = ~pat; + * if (p >= pe) break; + * p++; + * * if (++k >= 32) { * pat = lb; * k = 0; @@ -714,112 +809,108 @@ void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off) * pat = pat << 1; * pat |= sval; * } - * p++; * } */ asm __volatile__ ( - "pushl %%ebp\n\t" - "jmp L30\n\t" - - ".p2align 4,,7\n\t" - "L30:\n\t" - "movl (%%edi),%%ebp\n\t" - "cmpl %%ecx,%%ebp\n\t" - "jne L34\n\t" - -/* CDH start */ - "L35:\n\t" - "notl %%ecx\n\t" - "movl %%ecx,(%%edi)\n\t" - "notl %%ecx\n\t" - "addl $4,%%edi\n\t" - "incb %%bl\n\t" - "roll $1,%%ecx\n\t" - "cmpl %%edx,%%edi\n\t" - "jb L30\n\t" - "jmp L33\n\t" -/* CDH end */ - - "L34:\n\t" \ - "pushl %%esi\n\t" - "pushl %%eax\n\t" - "pushl %%ebx\n\t" - "pushl %%edx\n\t" - "pushl %%ebp\n\t" - "pushl %%ecx\n\t" - "pushl %%edi\n\t" - "call error\n\t" - "popl %%edi\n\t" - "popl %%ecx\n\t" - "popl %%ebp\n\t" - "popl %%edx\n\t" - "popl %%ebx\n\t" - "popl %%eax\n\t" - "popl %%esi\n\t" - "jmp L35\n" - -/* CDH start */ - "L33:\n\t" - "andb $31,%%bl\n\t" - "popl %%ebp\n\t" - : "=b" (k), "=D" (p), "=c" (pat) - : "D" (p),"d" (pe),"b" (k),"c" (pat) -/* CDH end */ + "pushl %%ebp\n\t" + "jmp L30\n\t" + ".p2align 4,,7\n\t" + "L930:\n\t" + "addl $4,%%edi\n\t" + "L30:\n\t" + "movl (%%edi),%%ebp\n\t" + "cmpl %%ecx,%%ebp\n\t" + "jne L34\n\t" + + "L35:\n\t" + "notl %%ecx\n\t" + "movl %%ecx,(%%edi)\n\t" + "notl %%ecx\n\t" + "incl %%ebx\n\t" + "cmpl $32,%%ebx\n\t" + "jne L31\n\t" + "movl %%esi,%%ecx\n\t" + "xorl %%ebx,%%ebx\n\t" + "jmp L32\n" + "L31:\n\t" + "shll $1,%%ecx\n\t" + "orl %%eax,%%ecx\n\t" + "L32:\n\t" + "cmpl %%edx,%%edi\n\t" + "jb L930\n\t" + "jmp L33\n\t" + + "L34:\n\t" \ + "pushl %%esi\n\t" + "pushl %%eax\n\t" + "pushl %%ebx\n\t" + "pushl %%edx\n\t" + "pushl %%ebp\n\t" + "pushl %%ecx\n\t" + "pushl %%edi\n\t" + "call error\n\t" + "popl %%edi\n\t" + "popl %%ecx\n\t" + "popl %%ebp\n\t" + "popl %%edx\n\t" + "popl %%ebx\n\t" + "popl %%eax\n\t" + "popl %%esi\n\t" + "jmp L35\n" + + "L33:\n\t" + "popl %%ebp\n\t" + : "=b" (k),"=c" (pat) + : "D" (p),"d" (pe),"b" (k),"c" (pat), + "a" (sval), "S" (lb) ); - do_tick(); - BAILR + p = pe + 1; } while (!done); } - /* Since we already adjusted k and the pattern this - * code backs both up one step - */ -/* CDH start */ -/* Original C code replaced with hand tuned assembly code - * pat = lb; - * if ( 0 != (k = (k-1) & 31) ) { - * pat = (pat << k); - * if ( sval ) - * pat |= ((sval << k) - 1); - * } - * k++; - */ - asm __volatile__ ( - "decl %%ecx\n\t" - "andl $31,%%ecx\n\t" - "roll %%cl,%%ebx\n\t" - "incb %%cl\n\t" - : "=c" (k), "=b" (pat) - : "c" (k), "b" (lb) - ); -/* CDH end */ + if (--k < 0) { + k = 31; + } + for (pat = lb, n = 0; n < k; n++) { + pat = pat << 1; + pat |= sval; + } + k++; for (j=segs-1; j>=0; j--) { - start = v->map[j].start; - end = v->map[j].end; - p = end -1; - pe = end -1; + calculate_chunk(&start, &end, me, j, 64); + p = end; + pe = end; done = 0; do { + do_tick(me); + BAILR + /* Check for underflow */ - if ((uintptr_t)(pe - SPINSZ) < (uintptr_t)pe) { - pe -= SPINSZ; - } else { - pe = start; - } - if ((uintptr_t)pe <= (uintptr_t)start) { + if (pe - SPINSZ < pe && pe != 0) { + pe -= SPINSZ; + } else { + pe = start; + done++; + } + /* We need this redundant check because we are + * using unsigned longs for the address. + */ + if (pe < start || pe > end) { pe = start; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code - * do { + * while(1) { * if ((bad=*p) != ~pat) { * error((ulong*)p, ~pat, bad); * } * *p = pat; + if (p >= pe) break; + p++; * if (--k <= 0) { * pat = hb; * k = 32; @@ -827,61 +918,62 @@ void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off) * pat = pat >> 1; * pat |= p3; * } - * } while (p-- > pe); + * }; */ asm __volatile__ ( - "pushl %%ebp\n\t" - "addl $4,%%edi\n\t" - "jmp L40\n\t" - - ".p2align 4,,7\n\t" - "L40:\n\t" - "subl $4,%%edi\n\t" - "movl (%%edi),%%ebp\n\t" - "notl %%ecx\n\t" - "cmpl %%ecx,%%ebp\n\t" - "jne L44\n\t" - -/* CDH start */ - "L45:\n\t" - "notl %%ecx\n\t" - "movl %%ecx,(%%edi)\n\t" - "decb %%bl\n\t" - "rorl $1,%%ecx\n\t" - "cmpl %%edx,%%edi\n\t" - "ja L40\n\t" - "jmp L43\n\t" -/* CDH end */ - - "L44:\n\t" \ - "pushl %%esi\n\t" - "pushl %%eax\n\t" - "pushl %%ebx\n\t" - "pushl %%edx\n\t" - "pushl %%ebp\n\t" - "pushl %%ecx\n\t" - "pushl %%edi\n\t" - "call error\n\t" - "popl %%edi\n\t" - "popl %%ecx\n\t" - "popl %%ebp\n\t" - "popl %%edx\n\t" - "popl %%ebx\n\t" - "popl %%eax\n\t" - "popl %%esi\n\t" - "jmp L45\n" - -/* CDH start */ - "L43:\n\t" - "andb $31,%%bl\n\t" - "subl $4,%%edi\n\t" - "popl %%ebp\n\t" - : "=b" (k), "=D" (p), "=c" (pat) - : "D" (p),"d" (pe),"b" (k),"c" (pat) -/* CDH end */ + "pushl %%ebp\n\t" + "jmp L40\n\t" + ".p2align 4,,7\n\t" + "L49:\n\t" + "subl $4,%%edi\n\t" + "L40:\n\t" + "movl (%%edi),%%ebp\n\t" + "notl %%ecx\n\t" + "cmpl %%ecx,%%ebp\n\t" + "jne L44\n\t" + + "L45:\n\t" + "notl %%ecx\n\t" + "movl %%ecx,(%%edi)\n\t" + "decl %%ebx\n\t" + "cmpl $0,%%ebx\n\t" + "jg L41\n\t" + "movl %%esi,%%ecx\n\t" + "movl $32,%%ebx\n\t" + "jmp L42\n" + "L41:\n\t" + "shrl $1,%%ecx\n\t" + "orl %%eax,%%ecx\n\t" + "L42:\n\t" + "cmpl %%edx,%%edi\n\t" + "ja L49\n\t" + "jmp L43\n\t" + + "L44:\n\t" \ + "pushl %%esi\n\t" + "pushl %%eax\n\t" + "pushl %%ebx\n\t" + "pushl %%edx\n\t" + "pushl %%ebp\n\t" + "pushl %%ecx\n\t" + "pushl %%edi\n\t" + "call error\n\t" + "popl %%edi\n\t" + "popl %%ecx\n\t" + "popl %%ebp\n\t" + "popl %%edx\n\t" + "popl %%ebx\n\t" + "popl %%eax\n\t" + "popl %%esi\n\t" + "jmp L45\n" + + "L43:\n\t" + "popl %%ebp\n\t" + : "=b" (k), "=c" (pat) + : "D" (p),"d" (pe),"b" (k),"c" (pat), + "a" (p3), "S" (hb) ); - do_tick(); - BAILR + p = pe - 1; } while (!done); } } @@ -890,40 +982,46 @@ void movinv32(int iter, ulong p1, ulong lb, ulong hb, int sval, int off) /* * Test all of memory using modulo X access pattern. */ -void modtst(int offset, int iter, ulong p1, ulong p2) +void modtst(int offset, int iter, ulong p1, ulong p2, int me) { int j, k, l, done; - volatile ulong *pe; - volatile ulong *start, *end; + ulong *p; + ulong *pe; + ulong *start, *end; /* Display the current pattern */ - hprint(LINE_PAT, COL_PAT-2, p1); - cprint(LINE_PAT, COL_PAT+6, "-"); - dprint(LINE_PAT, COL_PAT+7, offset, 2, 1); + if (mstr_cpu == me) { + hprint(LINE_PAT, COL_PAT-2, p1); + cprint(LINE_PAT, COL_PAT+6, "-"); + dprint(LINE_PAT, COL_PAT+7, offset, 2, 1); + } /* Write every nth location with pattern */ for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 4); + end -= MOD_SZ; /* adjust the ending address */ pe = (ulong *)start; p = start+offset; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code - * for (; p < pe; p += MOD_SZ) { + * for (; p <= pe; p += MOD_SZ) { * *p = p1; * } */ @@ -939,36 +1037,36 @@ void modtst(int offset, int iter, ulong p1, ulong p2) : "=D" (p) : "D" (p), "d" (pe), "a" (p1) ); - do_tick(); - BAILR } while (!done); } /* Write the rest of memory "iter" times with the pattern complement */ for (l=0; l<iter; l++) { for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 4); pe = (ulong *)start; p = start; done = 0; k = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code - * for (; p < pe; p++) { + * for (; p <= pe; p++) { * if (k != offset) { * *p = p2; * } @@ -981,6 +1079,8 @@ void modtst(int offset, int iter, ulong p1, ulong p2) "jmp L50\n\t" \ ".p2align 4,,7\n\t" \ + "L54:\n\t" \ + "addl $4,%%edi\n\t" \ "L50:\n\t" \ "cmpl %%ebx,%%ecx\n\t" \ "je L52\n\t" \ @@ -991,43 +1091,43 @@ void modtst(int offset, int iter, ulong p1, ulong p2) "jle L53\n\t" \ "xorl %%ebx,%%ebx\n\t" \ "L53:\n\t" \ - "addl $4,%%edi\n\t" \ "cmpl %%edx,%%edi\n\t" \ - "jb L50\n\t" \ - : "=D" (p), "=b" (k) + "jb L54\n\t" \ + : "=b" (k) : "D" (p), "d" (pe), "a" (p2), "b" (k), "c" (offset) ); - do_tick(); - BAILR + p = pe + 1; } while (!done); } } /* Now check every nth location */ for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; + calculate_chunk(&start, &end, me, j, 4); pe = (ulong *)start; p = start+offset; done = 0; + end -= MOD_SZ; /* adjust the ending address */ do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ) > (uintptr_t)pe) { + if (pe + SPINSZ > pe && pe != 0) { pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { - + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } /* Original C code replaced with hand tuned assembly code - * for (; p < pe; p += MOD_SZ) { + * for (; p <= pe; p += MOD_SZ) { * if ((bad=*p) != p1) { * error((ulong*)p, p1, bad); * } @@ -1064,211 +1164,231 @@ void modtst(int offset, int iter, ulong p1, ulong p2) : "D" (p), "d" (pe), "a" (p1) : "ecx" ); - do_tick(); - BAILR } while (!done); } - cprint(LINE_PAT, COL_PAT, " "); } - - /* - * Test memory using block moves + * Test memory using block moves * Adapted from Robert Redelmeier's burnBX test */ -void block_move(int iter) +void block_move(int iter, int me) { int i, j, done; ulong len; - volatile ulong p, pe, pp; - volatile ulong start, end; + ulong *p, *pe, pp; + ulong *start, *end; - cprint(LINE_PAT, COL_PAT-2, " "); + cprint(LINE_PAT, COL_PAT-2, " "); /* Initialize memory with the initial pattern. */ for (j=0; j<segs; j++) { - start = (ulong)v->map[j].start; -#ifdef USB_WAR - /* We can't do the block move test on low memory beacuase - * BIOS USB support clobbers location 0x410 and 0x4e0 - */ - if (start < 0x4f0) { - start = 0x4f0; - } -#endif - end = (ulong)v->map[j].end; + calculate_chunk(&start, &end, me, j, 64); + + // end is always xxxxxffc, so increment so that length calculations are correct + end = end + 1; + pe = start; p = start; + done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ*4) > (uintptr_t)pe) { - pe += SPINSZ*4; + if (pe + SPINSZ > pe && pe != 0) { + pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { - + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { - + if (p == pe ) { break; } len = ((ulong)pe - (ulong)p) / 64; + //len++; asm __volatile__ ( "jmp L100\n\t" ".p2align 4,,7\n\t" "L100:\n\t" + + // First loop eax is 0x00000001, edx is 0xfffffffe "movl %%eax, %%edx\n\t" "notl %%edx\n\t" - "movl %%eax,0(%%edi)\n\t" - "movl %%eax,4(%%edi)\n\t" - "movl %%eax,8(%%edi)\n\t" - "movl %%eax,12(%%edi)\n\t" - "movl %%edx,16(%%edi)\n\t" - "movl %%edx,20(%%edi)\n\t" - "movl %%eax,24(%%edi)\n\t" - "movl %%eax,28(%%edi)\n\t" - "movl %%eax,32(%%edi)\n\t" - "movl %%eax,36(%%edi)\n\t" - "movl %%edx,40(%%edi)\n\t" - "movl %%edx,44(%%edi)\n\t" - "movl %%eax,48(%%edi)\n\t" - "movl %%eax,52(%%edi)\n\t" - "movl %%edx,56(%%edi)\n\t" - "movl %%edx,60(%%edi)\n\t" - "rcll $1, %%eax\n\t" + + // Set a block of 64-bytes // First loop DWORDS are + "movl %%eax,0(%%edi)\n\t" // 0x00000001 + "movl %%eax,4(%%edi)\n\t" // 0x00000001 + "movl %%eax,8(%%edi)\n\t" // 0x00000001 + "movl %%eax,12(%%edi)\n\t" // 0x00000001 + "movl %%edx,16(%%edi)\n\t" // 0xfffffffe + "movl %%edx,20(%%edi)\n\t" // 0xfffffffe + "movl %%eax,24(%%edi)\n\t" // 0x00000001 + "movl %%eax,28(%%edi)\n\t" // 0x00000001 + "movl %%eax,32(%%edi)\n\t" // 0x00000001 + "movl %%eax,36(%%edi)\n\t" // 0x00000001 + "movl %%edx,40(%%edi)\n\t" // 0xfffffffe + "movl %%edx,44(%%edi)\n\t" // 0xfffffffe + "movl %%eax,48(%%edi)\n\t" // 0x00000001 + "movl %%eax,52(%%edi)\n\t" // 0x00000001 + "movl %%edx,56(%%edi)\n\t" // 0xfffffffe + "movl %%edx,60(%%edi)\n\t" // 0xfffffffe + + // rotate left with carry, + // second loop eax is 0x00000002 + // second loop edx is (~eax) 0xfffffffd + "rcll $1, %%eax\n\t" + + // Move current position forward 64-bytes (to start of next block) "leal 64(%%edi), %%edi\n\t" + + // Loop until end "decl %%ecx\n\t" "jnz L100\n\t" + : "=D" (p) : "D" (p), "c" (len), "a" (1) : "edx" ); - do_tick(); - BAILR } while (!done); } + s_barrier(); - /* Now move the data around + /* Now move the data around * First move the data up half of the segment size we are testing * Then move the data to the original location + 32 bytes */ for (j=0; j<segs; j++) { - start = (ulong)v->map[j].start; -#ifdef USB_WAR - /* We can't do the block move test on low memory beacuase - * BIOS USB support clobbers location 0x410 and 0x4e0 - */ - if (start < 0x4f0) { - start = 0x4f0; - } -#endif - end = (ulong)v->map[j].end; + calculate_chunk(&start, &end, me, j, 64); + + // end is always xxxxxffc, so increment so that length calculations are correct + end = end + 1; pe = start; p = start; done = 0; + do { + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ*4) > (uintptr_t)pe) { - pe += SPINSZ*4; + if (pe + SPINSZ > pe && pe != 0) { + pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } - pp = p + ((pe - p) / 2); - len = ((ulong)pe - (ulong)p) / 8; + pp = (ulong)p + (((ulong)pe - (ulong)p) / 2); // Mid-point of this block + len = ((ulong)pe - (ulong)p) / 8; // Half the size of this block in DWORDS for(i=0; i<iter; i++) { + do_tick(me); + BAILR asm __volatile__ ( "cld\n" "jmp L110\n\t" ".p2align 4,,7\n\t" "L110:\n\t" - "movl %1,%%edi\n\t" - "movl %0,%%esi\n\t" - "movl %2,%%ecx\n\t" + + // + // At the end of all this + // - the second half equals the inital value of the first half + // - the first half is right shifted 32-bytes (with wrapping) + // + + // Move first half to second half + "movl %1,%%edi\n\t" // Destionation, pp (mid point) + "movl %0,%%esi\n\t" // Source, p (start point) + "movl %2,%%ecx\n\t" // Length, len (size of a half in DWORDS) "rep\n\t" "movsl\n\t" + + // Move the second half, less the last 32-bytes. To the first half, offset plus 32-bytes "movl %0,%%edi\n\t" - "addl $32,%%edi\n\t" - "movl %1,%%esi\n\t" + "addl $32,%%edi\n\t" // Destination, p(start-point) plus 32 bytes + "movl %1,%%esi\n\t" // Source, pp(mid-point) "movl %2,%%ecx\n\t" - "subl $8,%%ecx\n\t" + "subl $8,%%ecx\n\t" // Length, len(size of a half in DWORDS) minus 8 DWORDS (32 bytes) "rep\n\t" "movsl\n\t" - "movl %0,%%edi\n\t" - "movl $8,%%ecx\n\t" + + // Move last 8 DWORDS (32-bytes) of the second half to the start of the first half + "movl %0,%%edi\n\t" // Destination, p(start-point) + // Source, 8 DWORDS from the end of the second half, left over by the last rep/movsl + "movl $8,%%ecx\n\t" // Length, 8 DWORDS (32-bytes) "rep\n\t" "movsl\n\t" + :: "g" (p), "g" (pp), "g" (len) : "edi", "esi", "ecx" ); - do_tick(); - BAILR } p = pe; } while (!done); } + s_barrier(); - /* Now check the data + /* Now check the data * The error checking is rather crude. We just check that the * adjacent words are the same. */ for (j=0; j<segs; j++) { - start = (ulong)v->map[j].start; -#ifdef USB_WAR - /* We can't do the block move test on low memory beacuase - * BIOS USB support clobbers location 0x4e0 and 0x410 - */ - if (start < 0x4f0) { - start = 0x4f0; - } -#endif - end = (ulong)v->map[j].end; + calculate_chunk(&start, &end, me, j, 64); + + // end is always xxxxxffc, so increment so that length calculations are correct + end = end + 1; pe = start; p = start; done = 0; do { + do_tick(me); + BAILR + /* Check for overflow */ - if ((uintptr_t)(pe + SPINSZ*4) > (uintptr_t)pe) { - pe += SPINSZ*4; + if (pe + SPINSZ > pe && pe != 0) { + pe += SPINSZ; } else { pe = end; } - if ((uintptr_t)pe >= (uintptr_t)end) { + if (pe >= end) { pe = end; done++; } - if ((uintptr_t)p == (uintptr_t)pe) { + if (p == pe ) { break; } + pe-=2; /* the last dwords to test are pe[0] and pe[1] */ asm __volatile__ ( "jmp L120\n\t" ".p2align 4,,7\n\t" + "L124:\n\t" + "addl $8,%%edi\n\t" // Next QWORD "L120:\n\t" + + // Compare adjacent DWORDS "movl (%%edi),%%ecx\n\t" "cmpl 4(%%edi),%%ecx\n\t" - "jnz L121\n\t" + "jnz L121\n\t" // Print error if they don't match + // Loop until end of block "L122:\n\t" - "addl $8,%%edi\n\t" "cmpl %%edx,%%edi\n\t" - "jb L120\n" + "jb L124\n" "jmp L123\n\t" "L121:\n\t" + // eax not used so we don't need to save it as per cdecl + // ecx is used but not restored, however we don't need it's value anymore after this point "pushl %%edx\n\t" "pushl 4(%%edi)\n\t" "pushl %%ecx\n\t" @@ -1283,79 +1403,104 @@ void block_move(int iter) : "D" (p), "d" (pe) : "ecx" ); - do_tick(); - BAILR } while (!done); } } /* - * Test memory for bit fade. + * Test memory for bit fade, fill memory with pattern. */ -#define STIME 5400 -void bit_fade() +void bit_fade_fill(ulong p1, int me) { - int j; - volatile ulong *pe; - volatile ulong bad; - volatile ulong *start,*end; - - test_ticks += (STIME * 2); - v->pass_ticks += (STIME * 2); + int j, done; + ulong *p, *pe; + ulong *start,*end; - /* Do -1 and 0 patterns */ - p1 = 0; - while (1) { + /* Display the current pattern */ + hprint(LINE_PAT, COL_PAT, p1); - /* Display the current pattern */ - hprint(LINE_PAT, COL_PAT, p1); + /* Initialize memory with the initial pattern. */ + for (j=0; j<segs; j++) { + start = v->map[j].start; + end = v->map[j].end; + pe = (ulong *)start; + p = start; + done = 0; + do { + do_tick(me); + BAILR - /* Initialize memory with the initial pattern. */ - for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; - pe = start; - p = start; - for (p=start; p<end; p++) { + /* Check for overflow */ + if (pe + SPINSZ > pe && pe != 0) { + pe += SPINSZ; + } else { + pe = end; + } + if (pe >= end) { + pe = end; + done++; + } + if (p == pe ) { + break; + } + for (; p < pe;) { *p = p1; + p++; } - do_tick(); + p = pe + 1; + } while (!done); + } +} + +void bit_fade_chk(ulong p1, int me) +{ + int j, done; + ulong *p, *pe, bad; + ulong *start,*end; + + /* Make sure that nothing changed while sleeping */ + for (j=0; j<segs; j++) { + start = v->map[j].start; + end = v->map[j].end; + pe = (ulong *)start; + p = start; + done = 0; + do { + do_tick(me); BAILR - } - /* Snooze for 90 minutes */ - sleep (STIME, 0); - /* Make sure that nothing changed while sleeping */ - for (j=0; j<segs; j++) { - start = v->map[j].start; - end = v->map[j].end; - pe = start; - p = start; - for (p=start; p<end; p++) { - if ((bad=*p) != p1) { + /* Check for overflow */ + if (pe + SPINSZ > pe && pe != 0) { + pe += SPINSZ; + } else { + pe = end; + } + if (pe >= end) { + pe = end; + done++; + } + if (p == pe ) { + break; + } + for (; p < pe;) { + if ((bad=*p) != p1) { error((ulong*)p, p1, bad); } + p++; } - do_tick(); - BAILR - } - if (p1 == 0) { - p1=-1; - } else { - break; - } + p = pe + 1; + } while (!done); } } -/* Sleep function */ -void sleep(int n, int sms) + +/* Sleep for N seconds */ +void sleep(long n, int flag, int me, int sms) { - int i, ip; - ulong sh, sl, l, h, t; + ulong sh, sl, l, h, t, ip=0; - ip = 0; /* save the starting time */ asm __volatile__( "rdtsc":"=a" (sl),"=d" (sh)); @@ -1363,6 +1508,7 @@ void sleep(int n, int sms) /* loop for n seconds */ while (1) { asm __volatile__( + "rep ; nop\n\t" "rdtsc":"=a" (l),"=d" (h)); asm __volatile__ ( "subl %2,%0\n\t" @@ -1378,31 +1524,21 @@ void sleep(int n, int sms) t = h * ((unsigned)0xffffffff / v->clks_msec) / 1000; t += (l / v->clks_msec) / 1000; } - + /* Is the time up? */ if (t >= n) { break; } - /* Display the elapsed time on the screen */ - if (sms == 0) { - - i = t % 60; - dprint(LINE_TIME, COL_TIME+9, i%10, 1, 0); - dprint(LINE_TIME, COL_TIME+8, i/10, 1, 0); - - if (i != ip) { - check_input(); - ip = i; - } + /* Only display elapsed time if flag is set */ + if (flag == 0) { + continue; + } - t /= 60; - i = t % 60; - dprint(LINE_TIME, COL_TIME+6, i % 10, 1, 0); - dprint(LINE_TIME, COL_TIME+5, i / 10, 1, 0); - t /= 60; - dprint(LINE_TIME, COL_TIME, t, 4, 0); + if (t != ip) { + do_tick(me); BAILR + ip = t; } } } @@ -1411,6 +1547,7 @@ void sleep(int n, int sms) void beep(unsigned int frequency) { + unsigned int count = 1193180 / frequency; // Switch on the speaker @@ -1424,7 +1561,7 @@ void beep(unsigned int frequency) outb((count >> 8) & 0xff, 0x42); // Block for 100 microseconds - sleep(100, 1); + sleep(100, 0, 0, 1); // Switch off the speaker outb(inb_p(0x61)&0xFC, 0x61); @@ -1,11 +1,7 @@ -/* test.h - MemTest-86 Version 3.2 +/* test.h - MemTest-86 Version 3.4 * * Released under version 2 of the Gnu Public License. * By Chris Brady - * ---------------------------------------------------- - * MemTest86+ V2.00 Specific code (GPL V2.0) - * By Samuel DEMEULEMEESTER, sdemeule@memtest.org - * http://www.canardpc.com - http://www.memtest.org */ #ifndef _TEST_H_ @@ -14,10 +10,9 @@ #define E801 0x04 #define E820NR 0x08 /* # entries in E820MAP */ #define E820MAP 0x0c /* our map */ -#define E820MAX 64 /* number of entries in E820MAP */ +#define E820MAX 127 /* number of entries in E820MAP */ #define E820ENTRY_SIZE 20 #define MEMINFO_SIZE (E820MAP + E820MAX * E820ENTRY_SIZE) -#define MAX_DMI_MEMDEVS 16 #ifndef __ASSEMBLY__ @@ -41,55 +36,65 @@ struct mem_info_t { }; typedef unsigned long ulong; -#define SPINSZ 0x2000000 +#define STACKSIZE (8*1024) +#define MAX_MEM 0x7FF00000 /* 8 TB */ +#define WIN_SZ 0x80000 /* 2 GB */ +#define UNMAP_SZ (0x100000-WIN_SZ) /* Size of umappped first segment */ + +#define SPINSZ 0x4000000 /* 256 MB */ #define MOD_SZ 20 -#define BAILOUT if (bail) goto skip_test; +#define BAILOUT if (bail) return(1); #define BAILR if (bail) return; -#define NULL 0 - -#define DMI_SEARCH_START 0x0000F000 -#define DMI_SEARCH_LENGTH 0x000F0FFF -#define MAX_DMI_MEMDEVS 16 #define RES_START 0xa0000 #define RES_END 0x100000 #define SCREEN_ADR 0xb8000 #define SCREEN_END_ADR (SCREEN_ADR + 80*25*2) -#define TITLE_WIDTH 28 -#define LINE_TIME 11 -#define COL_TIME 0 -#define LINE_TST 2 -#define LINE_RANGE 3 -#define LINE_CPU 1 +#define DMI_SEARCH_START 0x0000F000 +#define DMI_SEARCH_LENGTH 0x000F0FFF +#define MAX_DMI_MEMDEVS 16 + +#define TITLE_WIDTH 28 +#define LINE_TITLE 0 +#define LINE_TST 3 +#define LINE_RANGE 4 +#define LINE_PAT 5 +#define LINE_TIME 5 +#define LINE_STATUS 8 +#define LINE_INFO 9 +#define LINE_HEADER 12 +#define LINE_SCROLL 14 +#define LINE_SPD 14 +#define LINE_MSG 22 +#define LINE_CPU 7 +#define LINE_RAM 8 +#define LINE_DMI 23 +#define COL_INF1 15 +#define COL_INF2 32 +#define COL_INF3 51 +#define COL_INF4 70 +#define COL_MODE 15 #define COL_MID 30 -#define LINE_PAT 4 #define COL_PAT 41 -#define LINE_INFO 11 -#define COL_CACHE_TOP 13 -#define COL_RESERVED 22 -#define COL_MMAP 29 -#define COL_CACHE 40 -#define COL_ECC 46 -#define COL_TST 51 -#define COL_PASS 56 -#define COL_ERR 63 -#define COL_ECC_ERR 72 -#define LINE_HEADER 13 -#define LINE_SCROLL 15 #define BAR_SIZE (78-COL_MID-9) -#define LINE_MSG 18 -#define COL_MSG 18 +#define COL_MSG 23 +#define COL_TIME 67 +#define COL_SPEC 41 -#define POP_W 30 +#define POP_W 34 #define POP_H 15 -#define POP_X 16 +#define POP_X 11 #define POP_Y 8 -#define POP2_W 74 -#define POP2_H 21 -#define POP2_X 3 -#define POP2_Y 2 -//#define NULL 0 +#define POP2_W 74 +#define POP2_H 21 +#define POP2_X 3 +#define POP2_Y 2 + +/* CPU mode types */ +#define CPM_ALL 1 +#define CPM_RROBIN 2 +#define CPM_SEQ 3 /* memspeed operations */ #define MS_COPY 1 @@ -97,19 +102,21 @@ typedef unsigned long ulong; #define MS_READ 3 #define SZ_MODE_BIOS 1 -#define SZ_MODE_BIOS_RES 2 -#define SZ_MODE_PROBE 3 +#define SZ_MODE_PROBE 2 #define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); }) + int memcmp(const void *s1, const void *s2, ulong count); -int strncmp(const char *s1, const char *s2, ulong n); void *memmove(void *dest, const void *src, ulong n); +int strncmp(const char *s1, const char *s2, ulong n); +int strstr(char *str1, char *str2); +int strlen(char *string); int query_linuxbios(void); int query_pcbios(void); int insertaddress(ulong); void printpatn(void); void printpatn(void); -void itoa(char s[], int n); +void itoa(char s[], int n); void reverse(char *p); void serial_console_setup(char *param); void serial_echo_init(void); @@ -117,22 +124,22 @@ void serial_echo_print(const char *s); void ttyprint(int y, int x, const char *s); void ttyprintc(int y, int x, char c); void cprint(int y,int x, const char *s); -void hprint(int y,int x,ulong val); +void cplace(int y,int x, const char s); +void hprint(int y,int x, ulong val); void hprint2(int y,int x, ulong val, int len); void hprint3(int y,int x, ulong val, int len); void xprint(int y,int x,ulong val); void aprint(int y,int x,ulong page); void dprint(int y,int x,ulong val,int len, int right); -void movinv1(int iter, ulong p1, ulong p2); -void movinvr(); -void movinv32(int iter, ulong p1, ulong lb, ulong mb, int sval, int off); -void modtst(int off, int iter, ulong p1, ulong p2); +void movinv1(int iter, ulong p1, ulong p2, int cpu); +void movinvr(int cpu); +void movinv32(int iter, ulong p1, ulong lb, ulong mb, int sval, int off, + int cpu); +void modtst(int off, int iter, ulong p1, ulong p2, int cpu); void error(ulong* adr, ulong good, ulong bad); void ad_err1(ulong *adr1, ulong *adr2, ulong good, ulong bad); void ad_err2(ulong *adr, ulong bad); -void do_tick(void); -void rand_seed(int seed1, int seed2); -ulong rand(); +void do_tick(); void init(void); struct eregs; void inter(struct eregs *trap_regs); @@ -150,16 +157,14 @@ void pop2clear(void); void get_config(void); void get_menu(void); void get_printmode(void); -void addr_tst1(void); -void addr_tst2(void); -void bit_fade(void); -void sleep(int sec, int sms); -void beep(unsigned int frequency); +void addr_tst1(int cpu); +void addr_tst2(int cpu); int getnum(ulong val); -void block_move(int iter); +void sleep(long sec, int flag, int cpu, int sms); +void block_move(int iter, int cpu); void find_ticks(void); void print_err(ulong *adr, ulong good, ulong bad, ulong xor); -void print_ecc_err(ulong page, ulong offset, int corrected, +void print_ecc_err(ulong page, ulong offset, int corrected, unsigned short syndrome, int channel); void mem_size(void); void adj_mem(void); @@ -177,15 +182,19 @@ void show_spd(void); int map_page(unsigned long page); void *mapping(unsigned long page_address); void *emapping(unsigned long page_address); +int isdigit(char c); +ulong memspeed(ulong src, ulong len, int iter); unsigned long page_of(void *ptr); -ulong memspeed(ulong src, ulong len, int iter, int type); ulong correct_tsc(ulong el_org); +void bit_fade_fill(unsigned long n, int cpu); +void bit_fade_chk(unsigned long n, int cpu); +void find_ticks_for_pass(void); +void beep(unsigned int frequency); -#define PRINTMODE_SUMMARY 1 -#define PRINTMODE_ADDRESSES 0 +#define PRINTMODE_SUMMARY 0 +#define PRINTMODE_ADDRESSES 1 #define PRINTMODE_PATTERNS 2 #define PRINTMODE_NONE 3 -#define PRINTMODE_DMI 4 #define BADRAM_MAXPATNS 10 @@ -194,50 +203,27 @@ struct pair { ulong mask; }; - static inline void cache_off(void) { asm( "push %eax\n\t" "movl %cr0,%eax\n\t" - "orl $0x40000000,%eax\n\t" /* Set CD */ - "movl %eax,%cr0\n\t" + "orl $0x40000000,%eax\n\t" /* Set CD */ + "movl %eax,%cr0\n\t" "wbinvd\n\t" "pop %eax\n\t"); } + static inline void cache_on(void) { asm( "push %eax\n\t" "movl %cr0,%eax\n\t" - "andl $0x9fffffff,%eax\n\t" /* Clear CD and NW */ - "movl %eax,%cr0\n\t" + "andl $0x9fffffff,%eax\n\t" /* Clear CD and NW */ + "movl %eax,%cr0\n\t" "pop %eax\n\t"); } -static inline void reboot(void) -{ - asm( - "movl %cr0,%eax\n\t" - "andl $0x00000011,%eax\n\t" - "orl $0x60000000,%eax\n\t" - "movl %eax,%cr0\n\t" - "movl %eax,%cr3\n\t" - "movl %cr0,%ebx\n\t" - "andl $0x60000000,%ebx\n\t" - "jz f\n\t" - ".byte 0x0f,0x09\n\t" /* Invalidate and flush cache */ - "f: andb $0x10,%al\n\t" - "movl %eax,%cr0\n\t" - "movw $0x0010,%ax\n\t" - "movw %ax,%ds\n\t" - "movw %ax,%es\n\t" - "movw %ax,%fs\n\t" - "movw %ax,%gs\n\t" - "movw %ax,%ss\n\t" - "ljmp $0xffff,$0x0000\n\t"); -} - struct mmap { ulong pbase_addr; ulong *start; @@ -250,43 +236,14 @@ struct pmap { }; struct tseq { - short cache; + short sel; + short cpu_sel; short pat; short iter; short errors; char *msg; }; -struct cpu_ident { - char type; - char model; - char step; - char fill; - long cpuid; - long capability; - char vend_id[12]; - unsigned char cache_info[16]; - long pwrcap; - long ext; - long feature_flag; - long dcache0_eax; - long dcache0_ebx; - long dcache0_ecx; - long dcache0_edx; - long dcache1_eax; - long dcache1_ebx; - long dcache1_ecx; - long dcache1_edx; - long dcache2_eax; - long dcache2_ebx; - long dcache2_ecx; - long dcache2_edx; - long dcache3_eax; - long dcache3_ebx; - long dcache3_ecx; - long dcache3_edx; -}; - struct xadr { ulong page; ulong offset; @@ -306,31 +263,28 @@ struct err_info { short hdr_flag; }; + + #define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */ + #define MAX_MEM_SEGMENTS E820MAX -/* Define common variables accross relocations of memtest86+ */ +/* Define common variables accross relocations of memtest86 */ struct vars { - volatile int test; int pass; - unsigned long *eadr; - unsigned long exor; int msg_line; int ecount; int ecc_ecount; int msegs; int testsel; int scroll_start; - int rdtsc; - int pae; int pass_ticks; int total_ticks; int pptr; int tptr; - int beepmode; struct err_info erri; struct pmap pmap[MAX_MEM_SEGMENTS]; - struct mmap map[MAX_MEM_SEGMENTS]; + volatile struct mmap map[MAX_MEM_SEGMENTS]; ulong plim_lower; ulong plim_upper; ulong clks_msec; @@ -338,14 +292,16 @@ struct vars { ulong startl; ulong snaph; ulong snapl; - ulong extclock; - unsigned long imc_type; int printmode; int numpatn; struct pair patn [BADRAM_MAXPATNS]; ulong test_pages; ulong selected_pages; ulong reserved_pages; + int check_temp; + int fail_safe; + int each_sec; + int beepmode; }; #define FIRMWARE_UNKNOWN 0 @@ -358,10 +314,5 @@ extern unsigned char _size, _pages; extern struct mem_info_t mem_info; -/* CPU mode types */ -#define CPM_SINGLE 1 -#define CPM_RROBIN 2 -#define CPM_SEQ 3 - #endif /* __ASSEMBLY__ */ -#endif /* _TEST_H_ */
\ No newline at end of file +#endif /* _TEST_H_ */ diff --git a/version.number b/version.number new file mode 100644 index 0000000..6b0b9f8 --- /dev/null +++ b/version.number @@ -0,0 +1 @@ +4.99617 - Thu May 3 11:45:57 CEST 2012 @@ -0,0 +1,154 @@ +/* vmem.c - MemTest-86 + * + * Virtual memory handling (PAE) + * + * Released under version 2 of the Gnu Public License. + * By Chris Brady + */ +#include "stdint.h" +#include "test.h" +#include "cpuid.h" + +extern struct cpu_ident cpu_id; + +static unsigned long mapped_win = 1; +void paging_off(void) +{ + if (!cpu_id.fid.bits.pae) + return; + __asm__ __volatile__ ( + /* Disable paging */ + "movl %%cr0, %%eax\n\t" + "andl $0x7FFFFFFF, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + : : + : "ax" + ); +} + +static void paging_on(void *pdp) +{ + if (!cpu_id.fid.bits.pae) + return; + __asm__ __volatile__( + /* Load the page table address */ + "movl %0, %%cr3\n\t" + /* Enable paging */ + "movl %%cr0, %%eax\n\t" + "orl $0x80000000, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + : + : "r" (pdp) + : "ax" + ); +} + +static void paging_on_lm(void *pml) +{ + if (!cpu_id.fid.bits.pae) + return; + __asm__ __volatile__( + /* Load the page table address */ + "movl %0, %%cr3\n\t" + /* Enable paging */ + "movl %%cr0, %%eax\n\t" + "orl $0x80000000, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + : + : "r" (pml) + : "ax" + ); +} + +int map_page(unsigned long page) +{ + unsigned long i; + struct pde { + unsigned long addr_lo; + unsigned long addr_hi; + }; + extern unsigned char pdp[]; + extern unsigned char pml4[]; + extern struct pde pd2[]; + unsigned long win = page >> 19; + + /* Less than 2 GB so no mapping is required */ + if (win == 0) { + return 0; + } + if (cpu_id.fid.bits.pae == 0) { + /* Fail, we don't have PAE */ + return -1; + } + if (cpu_id.fid.bits.lm == 0 && (page > 0x1000000)) { + /* Fail, we want an address that is out of bounds (> 64GB) + * for PAE and no long mode (ie. 32 bit CPU). + */ + return -1; + } + /* Compute the page table entries... */ + for(i = 0; i < 1024; i++) { + /*-----------------10/30/2004 12:37PM--------------- + * 0xE3 -- + * Bit 0 = Present bit. 1 = PDE is present + * Bit 1 = Read/Write. 1 = memory is writable + * Bit 2 = Supervisor/User. 0 = Supervisor only (CPL 0-2) + * Bit 3 = Writethrough. 0 = writeback cache policy + * Bit 4 = Cache Disable. 0 = page level cache enabled + * Bit 5 = Accessed. 1 = memory has been accessed. + * Bit 6 = Dirty. 1 = memory has been written to. + * Bit 7 = Page Size. 1 = page size is 2 MBytes + * --------------------------------------------------*/ + pd2[i].addr_lo = ((win & 1) << 31) + ((i & 0x3ff) << 21) + 0xE3; + pd2[i].addr_hi = (win >> 1); + } + paging_off(); + if (cpu_id.fid.bits.lm == 1) { + paging_on_lm(pml4); + } else { + paging_on(pdp); + } + mapped_win = win; + return 0; +} + +void *mapping(unsigned long page_addr) +{ + void *result; + if (page_addr < 0x80000) { + /* If the address is less than 1GB directly use the address */ + result = (void *)(page_addr << 12); + } + else { + unsigned long alias; + alias = page_addr & 0x7FFFF; + alias += 0x80000; + result = (void *)(alias << 12); + } + return result; +} + +void *emapping(unsigned long page_addr) +{ + void *result; + result = mapping(page_addr -1); + /* Fill in the low address bits */ + result = ((unsigned char *)result) + 0xffc; + return result; +} + +unsigned long page_of(void *addr) +{ + unsigned long page; + page = ((unsigned long)addr) >> 12; + if (page >= 0x80000) { + page &= 0x7FFFF; + page += mapped_win << 19; + } +#if 0 + cprint(LINE_SCROLL -2, 0, "page_of( )-> "); + hprint(LINE_SCROLL -2, 8, ((unsigned long)addr)); + hprint(LINE_SCROLL -2, 20, page); +#endif + return page; +} |