From 541d4c97110cefeda23461c691e02dd2e431e609 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 27 Sep 2013 18:45:22 +0100 Subject: [import] Import version 5.01 http://www.memtest.org/download/5.01/memtest86+-5.01.tar.gz --- Makefile | 33 +- README | 1405 ++++++++++++++++++---------- README.background | 156 ++++ README.build-process | 78 +- build-number.txt | 1 + build.number | 1 + build_number.h | 9 + buildnumber.mak | 10 + changelog | 32 +- config.c | 360 +++---- config.h | 32 +- controller.c | 2543 +++++++++++++++++++++++++++++--------------------- controller.h | 15 + cpuid.c | 321 ++----- cpuid.h | 231 +++-- defs.h | 11 +- dmi.c | 125 ++- dmi.h | 1 + elf.h | 43 +- error.c | 322 ++++--- extra.c | 31 - head.S | 365 ++------ init.c | 1933 +++++++++++++++++--------------------- io.h | 1 - jedec_id.h | 1849 +++++++++++++++++++----------------- lib.c | 518 +++++----- main.c | 1488 ++++++++++++++++++++--------- major_version | 1 + make_buildnum.sh | 20 + makeiso.sh | 8 +- memsize.c | 197 +--- memtest.bin.lds | 30 +- memtest.lds | 22 +- memtest_shared.lds | 106 +-- msr.h | 23 +- mt86+_loader | Bin 784 -> 784 bytes mt86+_loader.asm | 4 +- patn.c | 2 +- pci.c | 58 +- pci.h | 1 + precomp.bin | Bin 164504 -> 150024 bytes random.c | 43 +- reloc.c | 31 +- screen_buffer.c | 83 +- screen_buffer.h | 5 - setup.S | 301 +++--- smp.c | 620 ++++++++---- smp.h | 159 +++- spd.c | 193 ++-- spd.h | 8 +- stddef.h | 8 + stdin.h | 52 ++ test.c | 1301 ++++++++++++++------------ test.h | 231 ++--- version.number | 1 + vmem.c | 154 +++ 56 files changed, 8740 insertions(+), 6836 deletions(-) create mode 100644 README.background create mode 100644 build-number.txt create mode 100644 build.number create mode 100644 build_number.h create mode 100644 buildnumber.mak create mode 100644 major_version create mode 100755 make_buildnum.sh create mode 100644 stddef.h create mode 100644 stdin.h create mode 100644 version.number create mode 100644 vmem.c diff --git a/Makefile b/Makefile index f51b813..9717a14 100644 --- a/Makefile +++ b/Makefile @@ -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 $(FDISK) bs=8192 @@ -71,4 +79,3 @@ install-precomp: dos: all cat mt86+_loader memtest.bin > memtest.exe - diff --git a/README b/README index 963cfc4..f9df887 100644 --- a/README +++ b/README @@ -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 +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 - +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 + 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) + diff --git a/changelog b/changelog index d6e49d2..9379a5b 100644 --- a/changelog +++ b/changelog @@ -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 + diff --git a/config.c b/config.c index 6d29004..18d8887 100644 --- a/config.c +++ b/config.c @@ -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 (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(); -} -*/ diff --git a/config.h b/config.h index e32eef4..aa4c9fb 100644 --- a/config.h +++ b/config.h @@ -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_timings_info(float cas, int rcd, int rp, int ras) { +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; + } - /* Now, we could print some additionnals timings infos) */ - cprint(LINE_CPU+6, col2 +1, "/ CAS : "); - col2 += 9; + 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_ram_line(float cas, int rcd, int rp, int ras, int chan) +{ + int cur_col = COL_SPEC; + + 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,77 +1561,264 @@ 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); - /* 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)"); - } + 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); - /* First, we need the clock ratio */ - pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); - temp2 = (dramchr & 0x1F); +} - switch (temp2) { - default: - case 6: - dramclock = 400; - break; - case 10: - dramclock = 533; - break; - case 14: - dramclock = 667; - break; - } +static void poll_fsb_k16(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 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_fsb_info(dramclock, "RAM : ", "DDR-"); + print_cpu_line(dramclock, fsb, 3); } -static void poll_fsb_i925(void) { +static void poll_fsb_k15(void) { - double dramclock, dramratio, fsb; - unsigned long mchcfg, mchcfg2, dev0, drc, idetect; - float coef = getP4PMmultiplier(); - long *ptr; + 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); - pci_conf_read( 0, 0, 0, 0x02, 2, &idetect); + /* 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_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); /* Find dramratio */ pci_conf_read( 0, 0, 0, 0x44, 4, &dev0); @@ -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 DRAM Freq + print_cpu_line(dramclock, fsb, 3); + +} - /* 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; +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_fsb_info(dramclock, "RAM : ", "DDR3-"); + 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_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); +} + +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; - cprint(LINE_CPU+6, col2+1, "/"); col2 +=2; + //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; } + ras = 16 - (3 * ((mtr1 >> 29) & 3)) + ((mtr1 >> 12) & 3); + if(((mtr1 >> 12) & 3) == 3 && ((mtr1 >> 29) & 3) == 2) { ras = 9; } - dprint(LINE_CPU+6, col2, temp, 1 ,0); - (temp < 10)?(col2 += 1):(col2 += 2); - - 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); +} + +static void poll_timings_k15(void) { + + 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); +} - print_timings_info(cas, rcd, rp, ras); +static void poll_timings_k16(void) { - cprint(LINE_CPU+6, col2, "/ DDR3 (64 bits)"); + 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 */ diff --git a/cpuid.c b/cpuid.c index 9a0843b..4c25ede 100644 --- a/cpuid.c +++ b/cpuid.c @@ -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 */ - } } diff --git a/cpuid.h b/cpuid.h index c35c2ba..caace1e 100644 --- a/cpuid.h +++ b/cpuid.h @@ -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; +}; + diff --git a/defs.h b/defs.h index e1a3350..3891699 100644 --- a/defs.h +++ b/defs.h @@ -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 */ diff --git a/dmi.c b/dmi.c index 0f05822..1f11008 100644 --- a/dmi.c +++ b/dmi.c @@ -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; jheader.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)"); + } } diff --git a/dmi.h b/dmi.h index a43a21f..c90fedd 100644 --- a/dmi.h +++ b/dmi.h @@ -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 diff --git a/elf.h b/elf.h index 78b5e9f..72efaac 100644 --- a/elf.h +++ b/elf.h @@ -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 */ diff --git a/error.c b/error.c index 5b63be0..4218d8c 100644 --- a/error.c +++ b/error.c @@ -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 +#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 */ @@ -280,86 +388,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 */ @@ -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; itest; i++) { + for (i=0, n=0; irdtsc) { + 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(); +*/ } + diff --git a/extra.c b/extra.c index e7afff2..ff580f2 100644 --- a/extra.c +++ b/extra.c @@ -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... // ///////////////////////////////////////////////////////// diff --git a/head.S b/head.S index 4a5c872..d551336 100644 --- a/head.S +++ b/head.S @@ -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 diff --git a/init.c b/init.c index f7f43c1..754b8d7 100644 --- a/init.c +++ b/init.c @@ -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("INE_SCROLL;24r"); /* Set scroll area row 7-23 */ + serial_echo_print(""); /* Clear Screen */ + serial_echo_print(""); + serial_echo_print(""); + serial_echo_print(""); /* 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); itest_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 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; ictype == 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 ; ifail_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; iclks_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; - } diff --git a/io.h b/io.h index 5d63437..4fda2de 100644 --- a/io.h +++ b/io.h @@ -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)) : \ diff --git a/jedec_id.h b/jedec_id.h index e62b343..b670f96 100644 --- a/jedec_id.h +++ b/jedec_id.h @@ -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, ""} }; diff --git a/lib.c b/lib.c index d107039..a2b829d 100644 --- a/lib.c +++ b/lib.c @@ -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); + } } /* @@ -235,6 +218,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 */ @@ -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> 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=" 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 diff --git a/main.c b/main.c index ea96f2d..0bc7ca0 100644 --- a/main.c +++ b/main.c @@ -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; ipmap[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>1) { - p1 = p0 | (p0<<8) | (p0<<16) | (p0<<24); + case 10: /* Modulo 20 check, Random pattern (test #10) */ + for (j=0; j>1) { + p1 = p0 | (p0<<8) | (p0<<16) | (p0<<24); for (i=0; i= 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; ((itestsel >= 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 diff --git a/makeiso.sh b/makeiso.sh index 0ed373e..ae5a8c9 100755 --- a/makeiso.sh +++ b/makeiso.sh @@ -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. " -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. " -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" diff --git a/memsize.c b/memsize.c index 3916538..0fea141 100644 --- a/memsize.c +++ b/memsize.c @@ -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; ipmap[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/ : { *(*) } +} diff --git a/msr.h b/msr.h index c904d50..af873a0 100644 --- a/msr.h +++ b/msr.h @@ -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 index 6c77a6f..030ea1a 100644 Binary files a/mt86+_loader and b/mt86+_loader differ 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) diff --git a/patn.c b/patn.c index 8240333..0c5b490 100644 --- a/patn.c +++ b/patn.c @@ -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 */ diff --git a/pci.c b/pci.c index e6c2cf6..075a07f 100644 --- a/pci.c +++ b/pci.c @@ -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); diff --git a/pci.h b/pci.h index 3629a6a..f21c478 100644 --- a/pci.h +++ b/pci.h @@ -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 index 293e15d..affaaab 100755 Binary files a/precomp.bin and b/precomp.bin differ diff --git a/random.c b/random.c index a0a19c7..69dd140 100644 --- a/random.c +++ b/random.c @@ -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; - } diff --git a/reloc.c b/reloc.c index 374b495..1b80731 100644 --- a/reloc.c +++ b/reloc.c @@ -1,7 +1,12 @@ -#include +/* 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 #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 diff --git a/setup.S b/setup.S index 056217f..f80875b 100644 --- a/setup.S +++ b/setup.S @@ -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) + diff --git a/smp.c b/smp.c index e49f52c..48fbb09 100644 --- a/smp.c +++ b/smp.c @@ -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)barrslock): "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"); } diff --git a/spd.c b/spd.c index cef93f0..fd3db9f 100644 --- a/spd.c +++ b/spd.c @@ -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) { diff --git a/spd.h b/spd.h index 7150381..55f164f 100644 --- a/spd.h +++ b/spd.h @@ -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 */ diff --git a/stdin.h b/stdin.h new file mode 100644 index 0000000..e3a08e1 --- /dev/null +++ b/stdin.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 diff --git a/test.c b/test.c index f30f3c4..a56d293 100644 --- a/test.c +++ b/test.c @@ -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 -#include "dmi.h" -#include -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; jmap[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 (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; jmap[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; jmap[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; jmap[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; imap[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; jmap[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; imap[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; jmap[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; lmap[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; jmap[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; jmap[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; jmap[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; imap[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; jmap[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; jmap[j].start; - end = v->map[j].end; - pe = start; - p = start; - for (p=start; p 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; jmap[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; jmap[j].start; - end = v->map[j].end; - pe = start; - p = start; - for (p=start; p 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); diff --git a/test.h b/test.h index 294c297..862da15 100644 --- a/test.h +++ b/test.h @@ -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 diff --git a/vmem.c b/vmem.c new file mode 100644 index 0000000..413d737 --- /dev/null +++ b/vmem.c @@ -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; +} -- cgit v1.2.3-55-g7522