mirror of
https://codeberg.org/libreboot/memtest86plus.git
synced 2025-07-03 15:57:06 +00:00
Compare commits
91 commits
v6.00-beta
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
5dcd424ea7 | ||
|
1f1fe5bfe8 | ||
|
0fd2e4c37a | ||
|
fa4e903509 | ||
|
bfbb167a72 | ||
|
79bb781431 | ||
|
c6b04e5414 | ||
|
5cbcd2046b | ||
|
bf0dae04bc | ||
|
dcca756e48 | ||
|
262aac4f85 | ||
|
66bd82f12a | ||
|
ee0c400821 | ||
|
e1fc02bfe0 | ||
|
a1d046fc3a | ||
|
1a38f513de | ||
|
22663f89bb | ||
|
c38b0cbc5f | ||
|
dfc41f7196 | ||
|
f62bbfde32 | ||
|
8305d47675 | ||
|
a47f681151 | ||
|
68e9542c1e | ||
|
ce2c29eddc | ||
|
b01c8e4388 | ||
|
d088740757 | ||
|
9c16a0568a | ||
|
040e253b54 | ||
|
2fa2346ae0 | ||
|
e5d7119abf | ||
|
a4c9adc445 | ||
|
485bfa46a3 | ||
|
b15a8bb632 | ||
|
327495ec61 | ||
|
8f788b27e1 | ||
|
f24e897883 | ||
|
3aeda70e24 | ||
|
b6992b9ec0 | ||
|
10e8435604 | ||
|
186ef6e913 | ||
|
d0399fd287 | ||
|
68deff493f | ||
|
1fca6dbcab | ||
|
a1af48a8cf | ||
|
03cd8d1898 | ||
|
d3d52b8a11 | ||
|
04980dfda3 | ||
|
d1014365c1 | ||
|
e022441544 | ||
|
3dd1fa8959 | ||
|
e3c0d6df60 | ||
|
87f03f3b10 | ||
|
f96c5b5093 | ||
|
59a0996070 | ||
|
da7b9b955d | ||
|
036922ab26 | ||
|
5a2bc4c960 | ||
|
9a86f115f4 | ||
|
0beb172a0d | ||
|
d3bc8fa7c2 | ||
|
1ee1078cf5 | ||
|
5036aa197a | ||
|
1278f02617 | ||
|
85213a9a27 | ||
|
83d08db69e | ||
|
aaa0cffaa6 | ||
|
66b1389348 | ||
|
407fb811c2 | ||
|
ddbee66c85 | ||
|
1c4d7f4089 | ||
|
c41159084d | ||
|
03a5222ee2 | ||
|
f265d1f1c5 | ||
|
18f12116c0 | ||
|
385f912776 | ||
|
6799bfba3c | ||
|
540270513f | ||
|
5686da4b1d | ||
|
43b0f64ddb | ||
|
0f8981412c | ||
|
93051adfc2 | ||
|
02702fa8c5 | ||
|
9660eead4e | ||
|
148dfd4d54 | ||
|
1316c6c099 | ||
|
8a3cac8133 | ||
|
408fdb8db6 | ||
|
13d9569041 | ||
|
740df34656 | ||
|
cf156adc4a | ||
|
53f61e6b87 |
69 changed files with 2336 additions and 1183 deletions
2
.github/workflows/Linux.yml
vendored
2
.github/workflows/Linux.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04]
|
||||
os: [ubuntu-20.04, ubuntu-22.04]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
|
2
.github/workflows/expired.yml
vendored
2
.github/workflows/expired.yml
vendored
|
@ -6,7 +6,7 @@ jobs:
|
|||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
exempt-issue-milestones: 'future,alpha,beta,release'
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,7 +8,7 @@
|
|||
*.o
|
||||
|
||||
# Generated file
|
||||
githash.h
|
||||
build_version.h
|
||||
|
||||
# Binaries
|
||||
memtest_shared
|
||||
|
|
69
README.md
69
README.md
|
@ -1,19 +1,21 @@
|
|||
---
|
||||
[DISCLAIMER] Memtest86+ v6.0 is NOT READY FOR PRODUCTION yet. The base code has basically been rewritten from scratch and many side functions are still under active development. A lot of additional beta-testing is needed. Please consider the actual code as experimental and expect crashes and freezes. Bugs reports are welcome and very helpful! Binary beta release are available on [memtest.org](https://memtest.org). The first production-ready stable release is planned for this summer.
|
||||
|
||||
---
|
||||
|
||||
# Memtest86+
|
||||
|
||||
Memtest86+ is a stand-alone memory tester for x86 and x86-64 architecture
|
||||
computers. It provides a more thorough memory check than that provided by
|
||||
BIOS memory tests.
|
||||
Memtest86+ is a free, open-source, stand-alone memory tester for x86 and
|
||||
x86-64 architecture computers. It provides a much more thorough memory
|
||||
check than that provided by BIOS memory tests.
|
||||
|
||||
It is also able to access almost all the computer's memory, not being
|
||||
restricted by the memory used by the operating system and not depending
|
||||
on any underlying software like UEFI libraries.
|
||||
|
||||
Memtest86+ can be loaded and run either directly by a PC BIOS (legacy or UEFI)
|
||||
or via an intermediate bootloader that supports the Linux 16-bit, 32-bit,
|
||||
64-bit, or EFI handover boot protocol. It should work on any Pentium class or
|
||||
later 32-bit or 64-bit CPU.
|
||||
|
||||
Binary releases (both stable and nightly dev builds) are available on
|
||||
[memtest.org](https://memtest.org).
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Origins](#origins)
|
||||
|
@ -28,23 +30,24 @@ later 32-bit or 64-bit CPU.
|
|||
* [Memtest86+ Test Algorithms](#memory-testing-philosophy)
|
||||
* [Individual Test Descriptions](#individual-test-descriptions)
|
||||
* [Known Limitations and Bugs](#known-limitations-and-bugs)
|
||||
* [Code Contributions](#code-contributions)
|
||||
* [Acknowledgments](#acknowledgments)
|
||||
|
||||
## Origins
|
||||
|
||||
Memtest86+ v6.0 was based on PCMemTest, which was a fork and rewrite of the
|
||||
earlier Memtest86+ v5.01, which in turn was a fork of Memtest86. The purpose
|
||||
Memtest86+ v6.00 was based on PCMemTest, which was a fork and rewrite of the
|
||||
earlier Memtest86+ v5, which in turn was a fork of MemTest-86. The purpose
|
||||
of the PCMemTest rewrite was to:
|
||||
|
||||
* make the code more readable and easier to maintain
|
||||
* make the code 64-bit clean and support UEFI boot
|
||||
* fix failures seen when building with newer versions of GCC
|
||||
|
||||
In the process of creating PCMemTest, a number of features of Memtest86+ v5.01
|
||||
In the process of creating PCMemTest, a number of features of Memtest86+ v5
|
||||
that were not strictly required for testing the system memory were dropped. In
|
||||
particular, no attempt is made to measure the cache and main memory speed, or
|
||||
to identify and report the DRAM type. These features will be added back
|
||||
in Memtest86+ v6.0 in an attempt to create an unified, fully-featured release.
|
||||
particular, no attempt was made to measure the cache and main memory speed, or
|
||||
to identify and report the DRAM type. These features were added back and expanded
|
||||
in Memtest86+ v6.0 to create a unified, fully-featured release.
|
||||
|
||||
## Licensing
|
||||
|
||||
|
@ -105,8 +108,10 @@ For test purposes, there is also an option to build an ISO image that uses
|
|||
GRUB as an intermediate bootloader. See the `Makefile` in the `build32` or
|
||||
`build64` directory for details. The ISO image is both legacy and UEFI
|
||||
bootable, so you need GRUB modules for both legacy and EFI boot installed
|
||||
on your build system. You may need to adjust some path and file names in
|
||||
the make file to match the naming on your system.
|
||||
on your build system (e.g. on Debian, the required GRUB modules are located
|
||||
in packages `grub-pc-bin`, `grub-efi-ia32-bin` and `grub-efi-amd64-bin`).
|
||||
You may need to adjust some path and file names in the Makefile to match
|
||||
the naming on your system.
|
||||
|
||||
The GRUB configuration files contained in the `grub` directory are there for
|
||||
use on the test ISO, but also serve as an example of how to boot Memtest86+
|
||||
|
@ -124,6 +129,8 @@ recognised:
|
|||
* disables ACPI table parsing and the use of multiple CPU cores
|
||||
* nobench
|
||||
* disables the integrated memory benchmark
|
||||
* nobigstatus
|
||||
* disables the big PASS/FAIL pop-up status display
|
||||
* nosm
|
||||
* disables SMBUS/SPD parsing, DMI decoding and memory benchmark
|
||||
* nopause
|
||||
|
@ -132,6 +139,7 @@ recognised:
|
|||
* where *type* is one of
|
||||
* legacy
|
||||
* usb
|
||||
* both
|
||||
* usbdebug
|
||||
* pauses after probing for USB keyboards
|
||||
* usbinit=*mode*
|
||||
|
@ -149,7 +157,7 @@ recognised:
|
|||
* 9600
|
||||
* 19200
|
||||
* 38400
|
||||
* 54600
|
||||
* 57600
|
||||
* 115200 (default if not specified or invalid)
|
||||
* 230400
|
||||
|
||||
|
@ -157,8 +165,9 @@ recognised:
|
|||
|
||||
Memtest86+ supports both the legacy keyboard interface (using I/O ports 0x60
|
||||
and 0x64) and USB keyboards (using its own USB device drivers). One or the
|
||||
other can be selected via the boot command line, If neither is selected, the
|
||||
default is to use both.
|
||||
other or both can be selected via the boot command line, If not specified on
|
||||
the command line, the default is to use both if the system was booted in UEFI
|
||||
mode, otherwise to only use the legacy interface.
|
||||
|
||||
Older BIOSs usually support USB legacy keyboard emulation, which makes USB
|
||||
keyboards act like legacy keyboards connected to ports 0x60 and 0x64. This
|
||||
|
@ -168,7 +177,8 @@ keyboards directly. The downside of that is that the USB controllers and
|
|||
device drivers require some memory to be reserved for their private use,
|
||||
which means that memory can't then be covered by the memory tests. So to
|
||||
maximise test coverage, if it is supported, enable USB legacy keyboard
|
||||
emulation and add `keyboard=legacy` on the boot command line.
|
||||
emulation and, if booting in UEFI mode, add `keyboard=legacy` on the boot
|
||||
command line.
|
||||
|
||||
**NOTE**: Some UEFI BIOSs only support USB legacy keyboard emulation when
|
||||
you enable the Compatibility System Module (CSM) in the BIOS setup. Others
|
||||
|
@ -178,8 +188,9 @@ Many USB devices don't fully conform to the USB specification. If the USB
|
|||
keyboard probe hangs or fails to detect your keyboard, try the various
|
||||
workarounds provided by the "usbinit" boot option.
|
||||
|
||||
**NOTE**: Memtest86+'s USB device drivers are work in progress. Not all USB
|
||||
devices are supported yet, and there may be problems on some hardware.
|
||||
**NOTE**: Hot-plugging is not currently supported by the Memtest86+ USB
|
||||
drivers. When using these, your USB keyboard should be plugged in before
|
||||
running Memtest86+ and should remain plugged in throughout the test.
|
||||
|
||||
## Operation
|
||||
|
||||
|
@ -472,8 +483,9 @@ selected by the user.
|
|||
|
||||
### Test 2 : Address test, own address + window
|
||||
|
||||
Across all memory regions, each address is written with its own address plus
|
||||
the window number and then each address is checked for consistency. This
|
||||
Across all memory regions, each address is written with its own virtual
|
||||
address plus the window number (for 32-bit images) or own physical address
|
||||
(for 64-bit images) and then each address is checked for consistency. This
|
||||
catches any errors in the high order address bits that would be missed when
|
||||
testing each window in turn. This test is performed sequentially with each
|
||||
available CPU, regardless of the CPU sequencing mode selected by the user.
|
||||
|
@ -537,10 +549,17 @@ of all zeros and all ones.
|
|||
|
||||
## Known Limitations and Bugs
|
||||
|
||||
* Keyboard may not be detected at launch in UEFI mode
|
||||
Please see the list of [open issues](https://github.com/memtest86plus/memtest86plus/issues)
|
||||
and [enhancement requests](https://github.com/memtest86plus/memtest86plus/discussions)
|
||||
on GitHub.
|
||||
|
||||
Feel free to submit bug reports!
|
||||
|
||||
## Code Contributions
|
||||
|
||||
Code contributions are welcomed, either to fix bugs or to make enhancements.
|
||||
See the README_DEVEL.md in the doc directory for some basic guidelines.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
Memtest86+ v6.0 was based on PCMemTest, developed by Martin Whitaker, which
|
||||
|
|
177
app/badram.c
177
app/badram.c
|
@ -34,6 +34,7 @@
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
#define MAX_PATTERNS 10
|
||||
#define PATTERNS_SIZE (MAX_PATTERNS + 1)
|
||||
|
||||
// DEFAULT_MASK covers a uintptr_t, since that is the testing granularity.
|
||||
#ifdef __x86_64__
|
||||
|
@ -55,14 +56,16 @@ typedef struct {
|
|||
// Private Variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static pattern_t pattern[MAX_PATTERNS];
|
||||
static pattern_t patterns[PATTERNS_SIZE];
|
||||
static int num_patterns = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define COMBINE_MASK(a,b,c,d) ((a & b & c & d) | (~a & b & ~c & d))
|
||||
// New mask is 1 where both masks were 1 (b & d) and the addresses were equal ~(a ^ c).
|
||||
// If addresses were unequal the new mask must be 0 to allow for both values.
|
||||
#define COMBINE_MASK(a,b,c,d) ((b & d) & ~(a ^ c))
|
||||
|
||||
/*
|
||||
* Combine two addr/mask pairs to one addr/mask pair.
|
||||
|
@ -72,7 +75,7 @@ static void combine(uintptr_t addr1, uintptr_t mask1, uintptr_t addr2, uintptr_t
|
|||
*mask = COMBINE_MASK(addr1, mask1, addr2, mask2);
|
||||
|
||||
*addr = addr1 | addr2;
|
||||
*addr &= *mask; // Normalise, no fundamental need for this
|
||||
*addr &= *mask; // Normalise to ensure sorting on .addr will work as intended
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -104,58 +107,110 @@ static uintptr_t combi_cost(uintptr_t addr1, uintptr_t mask1, uintptr_t addr2, u
|
|||
}
|
||||
|
||||
/*
|
||||
* Find the cheapest array index to extend with the given addr/mask pair.
|
||||
* Return -1 if nothing below the given minimum cost can be found.
|
||||
* Determine if pattern is already covered by an existing pattern.
|
||||
* Return true if that's the case, else false.
|
||||
*/
|
||||
static int cheap_index(uintptr_t addr1, uintptr_t mask1, uintptr_t min_cost)
|
||||
static bool is_covered(pattern_t pattern)
|
||||
{
|
||||
int i = num_patterns;
|
||||
int idx = -1;
|
||||
while (i-- > 0) {
|
||||
uintptr_t tmp_cost = combi_cost(pattern[i].addr, pattern[i].mask, addr1, mask1);
|
||||
if (tmp_cost < min_cost) {
|
||||
for (int i = 0; i < num_patterns; i++) {
|
||||
if (combi_cost(patterns[i].addr, patterns[i].mask, pattern.addr, pattern.mask) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the pair of entries that would be the cheapest to merge.
|
||||
* Assumes patterns is sorted by .addr asc and that for each index i, the cheapest entry to merge with is at i-1 or i+1.
|
||||
* Return -1 if <= 1 patterns exist, else the index of the first entry of the pair (the other being that + 1).
|
||||
*/
|
||||
static int cheapest_pair()
|
||||
{
|
||||
// This is guaranteed to be overwritten with >= 0 as long as num_patterns > 1
|
||||
int merge_idx = -1;
|
||||
|
||||
uintptr_t min_cost = UINTPTR_MAX;
|
||||
for (int i = 0; i < num_patterns - 1; i++) {
|
||||
uintptr_t tmp_cost = combi_cost(
|
||||
patterns[i].addr,
|
||||
patterns[i].mask,
|
||||
patterns[i+1].addr,
|
||||
patterns[i+1].mask
|
||||
);
|
||||
if (tmp_cost <= min_cost) {
|
||||
min_cost = tmp_cost;
|
||||
idx = i;
|
||||
merge_idx = i;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
return merge_idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find a relocation index for idx if it costs nothing.
|
||||
* Return -1 if no such index exists.
|
||||
* Remove entries at idx and idx+1.
|
||||
*/
|
||||
static int relocate_index(int idx)
|
||||
static void remove_pair(int idx)
|
||||
{
|
||||
uintptr_t addr = pattern[idx].addr;
|
||||
uintptr_t mask = pattern[idx].mask;
|
||||
pattern[idx].addr = ~pattern[idx].addr; // Never select idx
|
||||
int new = cheap_index(addr, mask, 1 + addresses(mask));
|
||||
pattern[idx].addr = addr;
|
||||
return new;
|
||||
for (int i = idx; i < num_patterns - 2; i++) {
|
||||
patterns[i] = patterns[i + 2];
|
||||
}
|
||||
patterns[num_patterns - 1].addr = 0u;
|
||||
patterns[num_patterns - 1].mask = 0u;
|
||||
patterns[num_patterns - 2].addr = 0u;
|
||||
patterns[num_patterns - 2].mask = 0u;
|
||||
num_patterns -= 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Relocate the given index idx only if free of charge.
|
||||
* This is useful to combine to `neighbouring' sections to integrate.
|
||||
* Inspired on the Buddy memalloc principle in the Linux kernel.
|
||||
* Get the combined entry of idx1 and idx2.
|
||||
*/
|
||||
static void relocate_if_free(int idx)
|
||||
static pattern_t combined_pattern(int idx1, int idx2)
|
||||
{
|
||||
int newidx = relocate_index(idx);
|
||||
if (newidx >= 0) {
|
||||
uintptr_t caddr, cmask;
|
||||
combine(pattern[newidx].addr, pattern[newidx].mask,
|
||||
pattern[ idx].addr, pattern[ idx].mask,
|
||||
&caddr, &cmask);
|
||||
pattern[newidx].addr = caddr;
|
||||
pattern[newidx].mask = cmask;
|
||||
if (idx < --num_patterns) {
|
||||
pattern[idx].addr = pattern[num_patterns].addr;
|
||||
pattern[idx].mask = pattern[num_patterns].mask;
|
||||
}
|
||||
relocate_if_free (newidx);
|
||||
pattern_t combined;
|
||||
combine(
|
||||
patterns[idx1].addr,
|
||||
patterns[idx1].mask,
|
||||
patterns[idx2].addr,
|
||||
patterns[idx2].mask,
|
||||
&combined.addr,
|
||||
&combined.mask
|
||||
);
|
||||
return combined;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert pattern at index idx, shuffling other entries on index towards the end.
|
||||
*/
|
||||
static void insert_at(pattern_t pattern, int idx)
|
||||
{
|
||||
// Move all entries >= idx one index towards the end to make space for the new entry
|
||||
for (int i = num_patterns - 1; i >= idx; i--) {
|
||||
patterns[i + 1] = patterns[i];
|
||||
}
|
||||
|
||||
patterns[idx] = pattern;
|
||||
num_patterns++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert entry (addr, mask) in patterns in an index i so that patterns[i-1].addr < patterns[i]
|
||||
* NOTE: Assumes patterns is already sorted by .addr asc!
|
||||
*/
|
||||
static void insert_sorted(pattern_t pattern)
|
||||
{
|
||||
// Normalise to ensure sorting on .addr will work as intended
|
||||
pattern.addr &= pattern.mask;
|
||||
|
||||
// Find index to insert entry into
|
||||
int new_idx = num_patterns;
|
||||
for (int i = 0; i < num_patterns; i++) {
|
||||
if (pattern.addr < patterns[i].addr) {
|
||||
new_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
insert_at(pattern, new_idx);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -165,26 +220,40 @@ static void relocate_if_free(int idx)
|
|||
void badram_init(void)
|
||||
{
|
||||
num_patterns = 0;
|
||||
|
||||
for (int idx = 0; idx < PATTERNS_SIZE; idx++) {
|
||||
patterns[idx].addr = 0u;
|
||||
patterns[idx].mask = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
bool badram_insert(uintptr_t addr)
|
||||
{
|
||||
if (cheap_index(addr, DEFAULT_MASK, 1) != -1) {
|
||||
pattern_t pattern = {
|
||||
.addr = addr,
|
||||
.mask = DEFAULT_MASK
|
||||
};
|
||||
|
||||
// If covered by existing entry we return immediately
|
||||
if (is_covered(pattern)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_patterns < MAX_PATTERNS) {
|
||||
pattern[num_patterns].addr = addr;
|
||||
pattern[num_patterns].mask = DEFAULT_MASK;
|
||||
num_patterns++;
|
||||
relocate_if_free(num_patterns - 1);
|
||||
} else {
|
||||
int idx = cheap_index(addr, DEFAULT_MASK, UINTPTR_MAX);
|
||||
uintptr_t caddr, cmask;
|
||||
combine(pattern[idx].addr, pattern[idx].mask, addr, DEFAULT_MASK, &caddr, &cmask);
|
||||
pattern[idx].addr = caddr;
|
||||
pattern[idx].mask = cmask;
|
||||
relocate_if_free(idx);
|
||||
// Add entry in order sorted by .addr asc
|
||||
insert_sorted(pattern);
|
||||
|
||||
// If we have more patterns than the max we need to force a merge
|
||||
if (num_patterns > MAX_PATTERNS) {
|
||||
// Find the pair that is the cheapest to merge
|
||||
// merge_idx will be -1 if num_patterns < 2, but that means MAX_PATTERNS = 0 which is not a valid state anyway
|
||||
int merge_idx = cheapest_pair();
|
||||
|
||||
pattern_t combined = combined_pattern(merge_idx, merge_idx + 1);
|
||||
|
||||
// Remove the source pair so that we can maintain order as combined does not necessarily belong in merge_idx
|
||||
remove_pair(merge_idx);
|
||||
|
||||
insert_sorted(combined);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -214,8 +283,8 @@ void badram_display(void)
|
|||
col = 7;
|
||||
}
|
||||
display_scrolled_message(col, "0x%0*x,0x%0*x",
|
||||
TESTWORD_DIGITS, pattern[i].addr,
|
||||
TESTWORD_DIGITS, pattern[i].mask);
|
||||
TESTWORD_DIGITS, patterns[i].addr,
|
||||
TESTWORD_DIGITS, patterns[i].mask);
|
||||
col += text_width;
|
||||
}
|
||||
}
|
||||
|
|
53
app/config.c
53
app/config.c
|
@ -91,6 +91,7 @@ bool exclude_ecores = true;
|
|||
|
||||
bool smp_enabled = true;
|
||||
|
||||
bool enable_big_status = true;
|
||||
bool enable_temperature = true;
|
||||
bool enable_trace = false;
|
||||
|
||||
|
@ -104,7 +105,9 @@ power_save_t power_save = POWER_SAVE_HIGH;
|
|||
bool enable_tty = false;
|
||||
int tty_params_port = SERIAL_PORT_0x3F8;
|
||||
int tty_params_baud = SERIAL_DEFAULT_BAUDRATE;
|
||||
int tty_update_period = 2; // Update TTY every 2 seconds (default)
|
||||
int tty_update_period = 2; // Update TTY every 2 seconds (default)
|
||||
|
||||
bool err_banner_redraw = false; // Redraw banner on new errors (if previsouly removed)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
|
@ -172,12 +175,46 @@ static void parse_option(const char *option, const char *params)
|
|||
{
|
||||
if (option[0] == '\0') return;
|
||||
|
||||
if (strncmp(option, "keyboard", 9) == 0 && params != NULL) {
|
||||
if (strncmp(option, "console", 8) == 0) {
|
||||
parse_serial_params(params);
|
||||
} else if (strncmp(option, "cpuseqmode", 11) == 0) {
|
||||
if (strncmp(params, "par", 4) == 0) {
|
||||
cpu_mode = PAR;
|
||||
} else if (strncmp(params, "seq", 4) == 0) {
|
||||
cpu_mode = SEQ;
|
||||
} else if (strncmp(params, "rr", 3) == 0 || strncmp(params, "one", 4) == 0) {
|
||||
cpu_mode = ONE;
|
||||
}
|
||||
} else if (strncmp(option, "reportmode", 11) == 0) {
|
||||
if (strncmp(params, "none", 5) == 0) {
|
||||
error_mode = ERROR_MODE_NONE;
|
||||
} else if (strncmp(params, "summary", 8) == 0) {
|
||||
error_mode = ERROR_MODE_SUMMARY;
|
||||
} else if (strncmp(params, "address", 8) == 0) {
|
||||
error_mode = ERROR_MODE_ADDRESS;
|
||||
} else if (strncmp(params, "badram", 7) == 0) {
|
||||
error_mode = ERROR_MODE_BADRAM;
|
||||
}
|
||||
} else if (strncmp(option, "keyboard", 9) == 0 && params != NULL) {
|
||||
if (strncmp(params, "legacy", 7) == 0) {
|
||||
keyboard_types = KT_LEGACY;
|
||||
} else if (strncmp(params, "usb", 4) == 0) {
|
||||
keyboard_types = KT_USB;
|
||||
} else if (strncmp(params, "both", 5) == 0) {
|
||||
keyboard_types = KT_USB|KT_LEGACY;
|
||||
}
|
||||
} else if (strncmp(option, "nobench", 8) == 0) {
|
||||
enable_bench = false;
|
||||
} else if (strncmp(option, "nobigstatus", 12) == 0) {
|
||||
enable_big_status = false;
|
||||
} else if (strncmp(option, "noehci", 7) == 0) {
|
||||
usb_init_options |= USB_IGNORE_EHCI;
|
||||
} else if (strncmp(option, "nopause", 8) == 0) {
|
||||
pause_at_start = false;
|
||||
} else if (strncmp(option, "nosm", 5) == 0) {
|
||||
enable_sm = false;
|
||||
} else if (strncmp(option, "nosmp", 6) == 0) {
|
||||
smp_enabled = false;
|
||||
} else if (strncmp(option, "powersave", 10) == 0) {
|
||||
if (strncmp(params, "off", 4) == 0) {
|
||||
power_save = POWER_SAVE_OFF;
|
||||
|
@ -186,16 +223,6 @@ static void parse_option(const char *option, const char *params)
|
|||
} else if (strncmp(params, "high", 5) == 0) {
|
||||
power_save = POWER_SAVE_HIGH;
|
||||
}
|
||||
} else if (strncmp(option, "console", 8) == 0) {
|
||||
parse_serial_params(params);
|
||||
} else if (strncmp(option, "nobench", 8) == 0) {
|
||||
enable_bench = false;
|
||||
} else if (strncmp(option, "noehci", 7) == 0) {
|
||||
usb_init_options |= USB_IGNORE_EHCI;
|
||||
} else if (strncmp(option, "nopause", 8) == 0) {
|
||||
pause_at_start = false;
|
||||
} else if (strncmp(option, "nosmp", 6) == 0) {
|
||||
smp_enabled = false;
|
||||
} else if (strncmp(option, "trace", 6) == 0) {
|
||||
enable_trace = true;
|
||||
} else if (strncmp(option, "usbdebug", 9) == 0) {
|
||||
|
@ -208,8 +235,6 @@ static void parse_option(const char *option, const char *params)
|
|||
} else if (strncmp(params, "3", 2) == 0) {
|
||||
usb_init_options |= USB_2_STEP_INIT|USB_EXTRA_RESET;
|
||||
}
|
||||
} else if (strncmp(option, "nosm", 5) == 0) {
|
||||
enable_sm = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ extern bool exclude_ecores;
|
|||
|
||||
extern bool smp_enabled;
|
||||
|
||||
extern bool enable_big_status;
|
||||
extern bool enable_temperature;
|
||||
extern bool enable_trace;
|
||||
|
||||
|
@ -66,6 +67,8 @@ extern int tty_params_port;
|
|||
extern int tty_params_baud;
|
||||
extern int tty_update_period;
|
||||
|
||||
extern bool err_banner_redraw;
|
||||
|
||||
void config_init(void);
|
||||
|
||||
void config_menu(bool initial);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "error.h"
|
||||
#include "githash.h"
|
||||
#include "build_version.h"
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
|||
#define POP_STAT_C 18
|
||||
|
||||
#define POP_STAT_W 44
|
||||
#define POP_STAT_H 9
|
||||
#define POP_STAT_H 11
|
||||
|
||||
#define POP_STAT_LAST_R (POP_STAT_R + POP_STAT_H - 1)
|
||||
#define POP_STAT_LAST_C (POP_STAT_C + POP_STAT_W - 1)
|
||||
|
@ -49,7 +49,7 @@
|
|||
|
||||
static const char spin_state[NUM_SPIN_STATES] = { '|', '/', '-', '\\' };
|
||||
|
||||
static const char *cpu_mode_str[] = { "PAR", "SEQ", "RR " };
|
||||
static const char cpu_mode_str[3][4] = { "PAR", "SEQ", "RR " };
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Variables
|
||||
|
@ -103,9 +103,9 @@ void display_init(void)
|
|||
set_foreground_colour(BLACK);
|
||||
set_background_colour(WHITE);
|
||||
clear_screen_region(0, 0, 0, 27);
|
||||
prints(0, 0, " Memtest86+ v6.00b3");
|
||||
prints(0, 0, " Memtest86+ v" MT_VERSION);
|
||||
set_foreground_colour(RED);
|
||||
printc(0, 14, '+');
|
||||
printc(0, 15, '+');
|
||||
set_foreground_colour(WHITE);
|
||||
set_background_colour(BLUE);
|
||||
prints(1, 0, "CLK/Temp: N/A | Pass %");
|
||||
|
@ -137,8 +137,7 @@ void display_init(void)
|
|||
set_background_colour(WHITE);
|
||||
clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1);
|
||||
prints(ROW_FOOTER, 0, " <ESC> Exit <F1> Configuration <Space> Scroll Lock");
|
||||
prints(ROW_FOOTER, 64, "6.00.");
|
||||
prints(ROW_FOOTER, 69, GIT_HASH);
|
||||
prints(ROW_FOOTER, 64, MT_VERSION "." GIT_HASH);
|
||||
#if TESTWORD_WIDTH > 32
|
||||
prints(ROW_FOOTER, 76, ".x64");
|
||||
#else
|
||||
|
@ -266,7 +265,7 @@ void post_display_init(void)
|
|||
if (false) {
|
||||
// Try to get RAM information from IMC (TODO)
|
||||
display_spec_mode("IMC: ");
|
||||
display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS);
|
||||
display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tCL_dec, ram.tRCD, ram.tRP, ram.tRAS);
|
||||
display_mode = DISPLAY_MODE_IMC;
|
||||
} else if (ram.freq > 0 && ram.tCL > 0) {
|
||||
// If not available, grab max memory specs from SPD
|
||||
|
@ -274,7 +273,7 @@ void post_display_init(void)
|
|||
if (ram.freq <= 166) {
|
||||
display_spec_sdr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS);
|
||||
} else {
|
||||
display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS);
|
||||
display_spec_ddr(ram.freq, ram.type, ram.tCL, ram.tCL_dec, ram.tRCD, ram.tRP, ram.tRAS);
|
||||
}
|
||||
display_mode = DISPLAY_MODE_SPD;
|
||||
} else {
|
||||
|
@ -356,7 +355,7 @@ void display_temperature(void)
|
|||
|
||||
void display_big_status(bool pass)
|
||||
{
|
||||
if (big_status_displayed) {
|
||||
if (!enable_big_status || big_status_displayed) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -383,6 +382,10 @@ void display_big_status(bool pass)
|
|||
prints(POP_STAT_R+6, POP_STAT_C+5, "## ## ## ## ## ");
|
||||
prints(POP_STAT_R+7, POP_STAT_C+5, "## ## ## ###### ###### ");
|
||||
}
|
||||
|
||||
prints(POP_STAT_R+8, POP_STAT_C+5, " ");
|
||||
prints(POP_STAT_R+9, POP_STAT_C+5, "Press any key to remove this banner ");
|
||||
|
||||
set_background_colour(BLUE);
|
||||
set_foreground_colour(WHITE);
|
||||
big_status_displayed = true;
|
||||
|
@ -390,6 +393,10 @@ void display_big_status(bool pass)
|
|||
|
||||
void restore_big_status(void)
|
||||
{
|
||||
if (!big_status_displayed) {
|
||||
return;
|
||||
}
|
||||
|
||||
restore_screen_region(POP_STATUS_REGION, popup_status_save_buffer);
|
||||
big_status_displayed = false;
|
||||
}
|
||||
|
@ -402,6 +409,7 @@ void check_input(void)
|
|||
return;
|
||||
} else if (big_status_displayed) {
|
||||
restore_big_status();
|
||||
enable_big_status = false;
|
||||
}
|
||||
|
||||
switch (input_key) {
|
||||
|
@ -509,7 +517,7 @@ void do_tick(int my_cpu)
|
|||
if (clks_per_msec > 0) {
|
||||
uint64_t current_time = get_tsc();
|
||||
|
||||
int secs = (current_time - run_start_time) / (1000 * clks_per_msec);
|
||||
int secs = (current_time - run_start_time) / (1000 * (uint64_t)clks_per_msec);
|
||||
int mins = secs / 60; secs %= 60; act_sec = secs;
|
||||
int hours = mins / 60; mins %= 60;
|
||||
display_run_time(hours, mins, secs);
|
||||
|
@ -534,6 +542,11 @@ void do_tick(int my_cpu)
|
|||
// This only tick one time per second
|
||||
if (!timed_update_done) {
|
||||
|
||||
// Display FAIL banner if (new) errors detected
|
||||
if (err_banner_redraw && !big_status_displayed && error_count > 1) {
|
||||
display_big_status(false);
|
||||
}
|
||||
|
||||
// Update temperature
|
||||
display_temperature();
|
||||
|
||||
|
|
|
@ -102,9 +102,9 @@ typedef enum {
|
|||
#define display_spec_mode(mode) \
|
||||
prints(8,0, mode);
|
||||
|
||||
#define display_spec_ddr(freq, type, cl, rcd, rp, ras) \
|
||||
printf(8,5, "%uMHz (%s-%u) CAS %u-%u-%u-%u", \
|
||||
freq / 2, type, freq, cl, rcd, rp, ras);
|
||||
#define display_spec_ddr(freq, type, cl, cl_dec, rcd, rp, ras) \
|
||||
printf(8,5, "%uMHz (%s-%u) CAS %u%s-%u-%u-%u", \
|
||||
freq / 2, type, freq, cl, cl_dec?".5":"", rcd, rp, ras);
|
||||
|
||||
#define display_spec_sdr(freq, type, cl, rcd, rp, ras) \
|
||||
printf(8,5, "%uMHz (%s PC%u) CAS %u-%u-%u-%u", \
|
||||
|
|
|
@ -151,6 +151,8 @@ static void common_err(error_type_t type, uintptr_t addr, testword_t good, testw
|
|||
{
|
||||
spin_lock(error_mutex);
|
||||
|
||||
restore_big_status();
|
||||
|
||||
bool new_header = (error_count == 0) || (error_mode != last_error_mode);
|
||||
if (new_header) {
|
||||
clear_message_area();
|
||||
|
@ -334,7 +336,7 @@ void addr_error(testword_t *addr1, testword_t *addr2, testword_t good, testword_
|
|||
void data_error(testword_t *addr, testword_t good, testword_t bad, bool use_for_badram)
|
||||
{
|
||||
#if USB_WORKAROUND
|
||||
/* Skip any errrors that appear to be due to the BIOS using location
|
||||
/* Skip any errors 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.
|
||||
|
@ -369,6 +371,7 @@ void error_update(void)
|
|||
display_error_count(error_count);
|
||||
display_status("Failed!");
|
||||
|
||||
// Display FAIL banner on first error
|
||||
if (error_count == 1) {
|
||||
display_big_status(false);
|
||||
}
|
||||
|
|
|
@ -251,10 +251,16 @@ static void global_init(void)
|
|||
|
||||
error_init();
|
||||
|
||||
temperature_init();
|
||||
|
||||
initial_config();
|
||||
|
||||
clear_message_area();
|
||||
|
||||
if (!smp_enabled) {
|
||||
num_available_cpus = 1;
|
||||
}
|
||||
|
||||
num_enabled_cpus = 0;
|
||||
for (int i = 0; i < num_available_cpus; i++) {
|
||||
if (cpu_state[i] == CPU_STATE_ENABLED) {
|
||||
|
@ -665,7 +671,8 @@ void main(void)
|
|||
if (error_count == 0) {
|
||||
display_status("Pass ");
|
||||
display_big_status(true);
|
||||
//display_notice("** Pass completed, no errors **");
|
||||
} else {
|
||||
display_big_status(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
app/version.h
Normal file
2
app/version.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define MT_VERSION "6.20"
|
||||
#define GIT_HASH "unknown"
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boot.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t orig_x;
|
||||
uint8_t orig_y;
|
||||
|
@ -56,6 +58,7 @@ typedef struct {
|
|||
|
||||
#define VIDEO_TYPE_VLFB 0x23 // VESA VGA in graphic mode
|
||||
#define VIDEO_TYPE_EFI 0x70 // EFI graphic mode
|
||||
#define VIDEO_TYPE_NONE 0xff // no video display (added for Memtest86+)
|
||||
|
||||
#define LFB_CAPABILITY_64BIT_BASE (1 << 1)
|
||||
|
||||
|
|
|
@ -334,9 +334,7 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
|||
|
||||
efi_graphics_output_t *gop = find_gop(handles, handles_size);
|
||||
if (!gop) {
|
||||
#if DEBUG
|
||||
print_string("GOP not found\n");
|
||||
#endif
|
||||
print_string("No graphics display found\n");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
@ -365,9 +363,7 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
|||
efi_call_bs(free_pool, info);
|
||||
}
|
||||
if (best_mode == UINT32_MAX) {
|
||||
#if DEBUG
|
||||
print_string("No suitable GOP screen resolution\n");
|
||||
#endif
|
||||
print_string("No suitable screen resolution found\n");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
@ -469,9 +465,7 @@ static efi_status_t set_screen_info_from_gop(screen_info_t *si, efi_handle_t *ha
|
|||
|
||||
status = efi_call_proto(gop, set_mode, best_mode);
|
||||
if (status != EFI_SUCCESS) {
|
||||
#if DEBUG
|
||||
print_string("Set GOP mode failed\n");
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -502,7 +496,16 @@ static efi_status_t set_screen_info(boot_params_t *boot_params)
|
|||
if (status == EFI_SUCCESS) {
|
||||
status = set_screen_info_from_gop(&boot_params->screen_info, handles, handles_size);
|
||||
}
|
||||
if (status == EFI_NOT_FOUND) {
|
||||
// This may be a headless system. We can still output to a serial console.
|
||||
boot_params->screen_info.orig_video_isVGA = VIDEO_TYPE_NONE;
|
||||
status = EFI_SUCCESS;
|
||||
}
|
||||
efi_call_bs(free_pool, handles);
|
||||
} else if (status == EFI_NOT_FOUND) {
|
||||
// This may be a headless system. We can still output to a serial console.
|
||||
boot_params->screen_info.orig_video_isVGA = VIDEO_TYPE_NONE;
|
||||
status = EFI_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
116
boot/header.S
116
boot/header.S
|
@ -7,7 +7,7 @@
|
|||
// end of the boot sector), with the remainder of the header being provided by
|
||||
// setup.S.
|
||||
//
|
||||
// Copyright (C) 2020 Martin Whitaker.
|
||||
// Copyright (C) 2020-2023 Martin Whitaker.
|
||||
//
|
||||
// Derived from Linux 5.6 arch/x86/boot/header.S:
|
||||
//
|
||||
|
@ -21,13 +21,13 @@
|
|||
#define __ASSEMBLY__
|
||||
|
||||
#include "boot.h"
|
||||
#include "peimage.h"
|
||||
|
||||
# The EFI loader loads the header at ImageBase, so we have to locate the main program
|
||||
# after that. This means we can't load the main program at HIGH_LOAD_ADDR. Pick a load
|
||||
# address well away from HIGH_LOAD_ADDR, to avoid overlap when relocating the code.
|
||||
|
||||
#define IMAGE_BASE 0x200000
|
||||
#define BASE_OF_CODE 0x1000
|
||||
|
||||
.section ".header", "ax", @progbits
|
||||
.code16
|
||||
|
@ -85,50 +85,46 @@ pe_header:
|
|||
|
||||
coff_header:
|
||||
#ifdef __x86_64__
|
||||
.word 0x8664 # Machine (x86-64)
|
||||
.word IMAGE_FILE_MACHINE_X64 # Machine (x86-64)
|
||||
#else
|
||||
.word 0x14c # Machine (i386)
|
||||
.word IMAGE_FILE_MACHINE_I386 # Machine (i386)
|
||||
#endif
|
||||
.word 1 # NumberOfSections
|
||||
.word 3 # NumberOfSections
|
||||
.long 0 # TimeDateStamp
|
||||
.long 0 # PointerToSymbolTable
|
||||
.long 0 # NumberOfSymbols
|
||||
.word section_table - optional_header # SizeOfOptionalHeader
|
||||
#ifdef __x86_64__
|
||||
.word 0x20f # Characteristics
|
||||
# IMAGE_FILE_DEBUG_STRIPPED |
|
||||
# IMAGE_FILE_LOCAL_SYMS_STRIPPED |
|
||||
# IMAGE_FILE_LINE_NUMS_STRIPPED |
|
||||
# IMAGE_FILE_EXECUTABLE_IMAGE |
|
||||
# IMAGE_FILE_RELOCS_STRIPPED
|
||||
.word IMAGE_FILE_DEBUG_STRIPPED \
|
||||
| IMAGE_FILE_LOCAL_SYMS_STRIPPED \
|
||||
| IMAGE_FILE_LINE_NUMS_STRIPPED \
|
||||
| IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics
|
||||
#else
|
||||
.word 0x30f # Characteristics.
|
||||
# IMAGE_FILE_32BIT_MACHINE |
|
||||
# IMAGE_FILE_DEBUG_STRIPPED |
|
||||
# IMAGE_FILE_LOCAL_SYMS_STRIPPED |
|
||||
# IMAGE_FILE_LINE_NUMS_STRIPPED |
|
||||
# IMAGE_FILE_EXECUTABLE_IMAGE |
|
||||
# IMAGE_FILE_RELOCS_STRIPPED
|
||||
.word IMAGE_FILE_32BIT_MACHINE \
|
||||
| IMAGE_FILE_DEBUG_STRIPPED \
|
||||
| IMAGE_FILE_LOCAL_SYMS_STRIPPED \
|
||||
| IMAGE_FILE_LINE_NUMS_STRIPPED \
|
||||
| IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics.
|
||||
#endif
|
||||
|
||||
optional_header:
|
||||
#ifdef __x86_64__
|
||||
.word 0x20b # PE32+ format
|
||||
.word IMAGE_NT_OPTIONAL_HDR64_MAGIC # PE32+ format
|
||||
#else
|
||||
.word 0x10b # PE32 format
|
||||
.word IMAGE_NT_OPTIONAL_HDR32_MAGIC # PE32 format
|
||||
#endif
|
||||
.byte 0x02 # MajorLinkerVersion
|
||||
.byte 0x14 # MinorLinkerVersion
|
||||
|
||||
.long _text_size # SizeOfCode
|
||||
.long 0 # SizeOfInitializedData
|
||||
.long _virt_text_size # SizeOfCode
|
||||
.long _virt_sbat_size # SizeOfInitializedData
|
||||
.long 0 # SizeOfUninitializedData
|
||||
|
||||
.long BASE_OF_CODE + 0x1e0 # AddressOfEntryPoint
|
||||
.long _virt_text_start + 0x1e0 # AddressOfEntryPoint
|
||||
|
||||
.long BASE_OF_CODE # BaseOfCode
|
||||
.long _virt_text_start # BaseOfCode
|
||||
#ifndef __x86_64__
|
||||
.long 0 # data
|
||||
.long _virt_sbat_start # BaseOfData
|
||||
#endif
|
||||
|
||||
extra_header_fields:
|
||||
|
@ -147,8 +143,8 @@ extra_header_fields:
|
|||
.word 0 # MinorSubsystemVersion
|
||||
.long 0 # Win32VersionValue
|
||||
|
||||
.long BASE_OF_CODE + _init_size # SizeOfImage
|
||||
.long 512 # SizeOfHeaders
|
||||
.long _virt_img_size # SizeOfImage
|
||||
.long _file_head_size # SizeOfHeaders
|
||||
.long 0 # CheckSum
|
||||
.word 10 # Subsystem (EFI application)
|
||||
.word 0 # DllCharacteristics
|
||||
|
@ -164,7 +160,20 @@ extra_header_fields:
|
|||
.long 0 # SizeOfHeapCommit
|
||||
#endif
|
||||
.long 0 # LoaderFlags
|
||||
.long 0 # NumberOfRvaAndSizes
|
||||
.long IMAGE_DIRECTORY_ENTRY_DEBUG # NumberOfRvaAndSizes
|
||||
|
||||
.long 0 # DataDirectory.Export.VirtualAddress
|
||||
.long 0 # DataDirectory.Export.Size
|
||||
.long 0 # DataDirectory.Import.VirtualAddress
|
||||
.long 0 # DataDirectory.Import.Size
|
||||
.long 0 # DataDirectory.Resource.VirtualAddress
|
||||
.long 0 # DataDirectory.Resource.Size
|
||||
.long 0 # DataDirectory.Exception.VirtualAddress
|
||||
.long 0 # DataDirectory.Exception.Size
|
||||
.long 0 # DataDirectory.Certs.VirtualAddress
|
||||
.long 0 # DataDirectory.Certs.Size
|
||||
.long _virt_reloc_start # DataDirectory.BaseReloc.VirtualAddress
|
||||
.long _real_reloc_size # DataDirectory.BaseReloc.Size
|
||||
|
||||
# Section table
|
||||
section_table:
|
||||
|
@ -172,15 +181,46 @@ section_table:
|
|||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.long _text_size # VirtualSize
|
||||
.long BASE_OF_CODE # VirtualAddress
|
||||
.long _text_size # SizeOfRawData
|
||||
.long _text_start # PointerToRawData
|
||||
.long _virt_text_size # VirtualSize
|
||||
.long _virt_text_start # VirtualAddress
|
||||
.long _file_text_size # SizeOfRawData
|
||||
.long _file_text_start # PointerToRawData
|
||||
.long 0 # PointerToRelocations
|
||||
.long 0 # PointerToLineNumbers
|
||||
.word 0 # NumberOfRelocations
|
||||
.word 0 # NumberOfLineNumbers
|
||||
.long 0x60500020 # Characteristics (section flags)
|
||||
.long IMAGE_SCN_MEM_READ \
|
||||
| IMAGE_SCN_MEM_EXECUTE \
|
||||
| IMAGE_SCN_CNT_CODE # Characteristics (section flags)
|
||||
|
||||
.ascii ".reloc"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.long _virt_reloc_size # VirtualSize
|
||||
.long _virt_reloc_start # VirtualAddress
|
||||
.long _file_reloc_size # SizeOfRawData
|
||||
.long _file_reloc_start # PointerToRawData
|
||||
.long 0 # PointerToRelocations
|
||||
.long 0 # PointerToLineNumbers
|
||||
.word 0 # NumberOfRelocations
|
||||
.word 0 # NumberOfLineNumbers
|
||||
.long IMAGE_SCN_MEM_READ \
|
||||
| IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags)
|
||||
|
||||
.ascii ".sbat"
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.long _virt_sbat_size # VirtualSize
|
||||
.long _virt_sbat_start # VirtualAddress
|
||||
.long _file_sbat_size # SizeOfRawData
|
||||
.long _file_sbat_start # PointerToRawData
|
||||
.long 0 # PointerToRelocations
|
||||
.long 0 # PointerToLineNumbers
|
||||
.word 0 # NumberOfRelocations
|
||||
.word 0 # NumberOfLineNumbers
|
||||
.long IMAGE_SCN_MEM_READ \
|
||||
| IMAGE_SCN_CNT_INITIALIZED_DATA # Characteristics (section flags)
|
||||
|
||||
# Emulate the Linux boot header, to allow loading by intermediate boot loaders.
|
||||
|
||||
|
@ -199,3 +239,13 @@ root_dev:
|
|||
.word 0
|
||||
boot_flag:
|
||||
.word 0xAA55
|
||||
|
||||
.org 512
|
||||
|
||||
.section ".reloc"
|
||||
.long 0 // Page RVA
|
||||
.long 10 // Block Size (2*4+2)
|
||||
.word (IMAGE_REL_BASED_ABSOLUTE << 12) + 0 // reloc 0 -> 0
|
||||
|
||||
.section ".sbat", "a", @progbits
|
||||
.incbin "../boot/sbat.csv"
|
||||
|
|
292
boot/peimage.h
Normal file
292
boot/peimage.h
Normal file
|
@ -0,0 +1,292 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// This is include/coff/pe.h from binutils-2.10.0.18
|
||||
// Copyright The Free Software Foundation
|
||||
|
||||
/* PE COFF header information */
|
||||
|
||||
#ifndef _PE_H
|
||||
#define _PE_H
|
||||
|
||||
/* NT specific file attributes. */
|
||||
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
|
||||
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
|
||||
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
|
||||
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
|
||||
#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
|
||||
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
|
||||
#define IMAGE_FILE_16BIT_MACHINE 0x0040
|
||||
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
|
||||
#define IMAGE_FILE_32BIT_MACHINE 0x0100
|
||||
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
|
||||
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
|
||||
#define IMAGE_FILE_SYSTEM 0x1000
|
||||
#define IMAGE_FILE_DLL 0x2000
|
||||
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
|
||||
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
|
||||
|
||||
/* Additional flags to be set for section headers to allow the NT loader to
|
||||
read and write to the section data (to replace the addresses of data in
|
||||
dlls for one thing); also to execute the section in .text's case. */
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
/* Section characteristics added for ppc-nt. */
|
||||
|
||||
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */
|
||||
|
||||
#define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */
|
||||
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */
|
||||
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */
|
||||
|
||||
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */
|
||||
#define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */
|
||||
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */
|
||||
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */
|
||||
|
||||
#define IMAGE_SCN_MEM_FARDATA 0x00008000
|
||||
|
||||
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
|
||||
#define IMAGE_SCN_MEM_16BIT 0x00020000
|
||||
#define IMAGE_SCN_MEM_LOCKED 0x00040000
|
||||
#define IMAGE_SCN_MEM_PRELOAD 0x00080000
|
||||
|
||||
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
|
||||
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
|
||||
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
|
||||
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
|
||||
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default alignment if no others are specified. */
|
||||
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
|
||||
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
|
||||
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
|
||||
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
|
||||
#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000
|
||||
#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
|
||||
#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
|
||||
#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
|
||||
#define IMAGE_SCN_ALIGN_8129BYTES 0x00e00000
|
||||
|
||||
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
|
||||
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
|
||||
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
|
||||
#define IMAGE_SCN_MEM_SHARED 0x10000000
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */
|
||||
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */
|
||||
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */
|
||||
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */
|
||||
|
||||
#define IMAGE_REL_BASED_ABSOLUTE 0x0000
|
||||
|
||||
/* COMDAT selection codes. */
|
||||
|
||||
#define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */
|
||||
#define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */
|
||||
#define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */
|
||||
#define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */
|
||||
#define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */
|
||||
|
||||
/* Machine numbers. */
|
||||
|
||||
#define IMAGE_FILE_MACHINE_UNKNOWN 0x0
|
||||
#define IMAGE_FILE_MACHINE_ALPHA 0x184
|
||||
#define IMAGE_FILE_MACHINE_ARM 0x1c0
|
||||
#define IMAGE_FILE_MACHINE_ALPHA64 0x284
|
||||
#define IMAGE_FILE_MACHINE_I386 0x14c
|
||||
#define IMAGE_FILE_MACHINE_IA64 0x200
|
||||
#define IMAGE_FILE_MACHINE_M68K 0x268
|
||||
#define IMAGE_FILE_MACHINE_MIPS16 0x266
|
||||
#define IMAGE_FILE_MACHINE_MIPSFPU 0x366
|
||||
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x466
|
||||
#define IMAGE_FILE_MACHINE_POWERPC 0x1f0
|
||||
#define IMAGE_FILE_MACHINE_R3000 0x162
|
||||
#define IMAGE_FILE_MACHINE_R4000 0x166
|
||||
#define IMAGE_FILE_MACHINE_R10000 0x168
|
||||
#define IMAGE_FILE_MACHINE_SH3 0x1a2
|
||||
#define IMAGE_FILE_MACHINE_SH4 0x1a6
|
||||
#define IMAGE_FILE_MACHINE_ARMTHUMB_MIXED 0x1c2
|
||||
#define IMAGE_FILE_MACHINE_X64 0x8664
|
||||
#define IMAGE_FILE_MACHINE_ARM64 0xaa64
|
||||
|
||||
#define IMAGE_SUBSYSTEM_UNKNOWN 0
|
||||
#define IMAGE_SUBSYSTEM_NATIVE 1
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
|
||||
#define IMAGE_SUBSYSTEM_POSIX_CUI 7
|
||||
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
|
||||
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
|
||||
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
|
||||
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
|
||||
|
||||
/* Magic values that are true for all dos/nt implementations */
|
||||
#define DOSMAGIC 0x5a4d
|
||||
#define NT_SIGNATURE 0x00004550
|
||||
|
||||
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b
|
||||
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b
|
||||
|
||||
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
|
||||
|
||||
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
|
||||
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
|
||||
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
|
||||
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
|
||||
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
|
||||
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
|
||||
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
|
||||
#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7
|
||||
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
|
||||
#define IMAGE_DIRECTORY_ENTRY_TLS 9
|
||||
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
|
||||
|
||||
#define IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
|
||||
|
||||
/* NT allows long filenames, we want to accommodate this. This may break
|
||||
some of the bfd functions */
|
||||
#undef FILNMLEN
|
||||
#define FILNMLEN 18 /* # characters in a file name */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
struct external_PEI_filehdr
|
||||
{
|
||||
/* DOS header fields - always at offset zero in the EXE file */
|
||||
char e_magic[2]; /* Magic number, 0x5a4d */
|
||||
char e_cblp[2]; /* Bytes on last page of file, 0x90 */
|
||||
char e_cp[2]; /* Pages in file, 0x3 */
|
||||
char e_crlc[2]; /* Relocations, 0x0 */
|
||||
char e_cparhdr[2]; /* Size of header in paragraphs, 0x4 */
|
||||
char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0 */
|
||||
char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF */
|
||||
char e_ss[2]; /* Initial (relative) SS value, 0x0 */
|
||||
char e_sp[2]; /* Initial SP value, 0xb8 */
|
||||
char e_csum[2]; /* Checksum, 0x0 */
|
||||
char e_ip[2]; /* Initial IP value, 0x0 */
|
||||
char e_cs[2]; /* Initial (relative) CS value, 0x0 */
|
||||
char e_lfarlc[2]; /* File address of relocation table, 0x40 */
|
||||
char e_ovno[2]; /* Overlay number, 0x0 */
|
||||
char e_res[4][2]; /* Reserved words, all 0x0 */
|
||||
char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0 */
|
||||
char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0 */
|
||||
char e_res2[10][2]; /* Reserved words, all 0x0 */
|
||||
char e_lfanew[4]; /* File address of new exe header, usually 0x80 */
|
||||
char dos_message[16][4]; /* other stuff, always follow DOS header */
|
||||
|
||||
/* Note: additional bytes may be inserted before the signature. Use
|
||||
the e_lfanew field to find the actual location of the NT signature */
|
||||
|
||||
char nt_signature[4]; /* required NT signature, 0x4550 */
|
||||
|
||||
/* From standard header */
|
||||
|
||||
char f_magic[2]; /* magic number */
|
||||
char f_nscns[2]; /* number of sections */
|
||||
char f_timdat[4]; /* time & date stamp */
|
||||
char f_symptr[4]; /* file pointer to symtab */
|
||||
char f_nsyms[4]; /* number of symtab entries */
|
||||
char f_opthdr[2]; /* sizeof(optional hdr) */
|
||||
char f_flags[2]; /* flags */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef COFF_IMAGE_WITH_PE
|
||||
|
||||
/* The filehdr is only weird in images. */
|
||||
|
||||
#undef FILHDR
|
||||
#define FILHDR struct external_PEI_filehdr
|
||||
#undef FILHSZ
|
||||
#define FILHSZ 152
|
||||
|
||||
#endif /* COFF_IMAGE_WITH_PE */
|
||||
|
||||
/* 32-bit PE a.out header: */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
typedef struct
|
||||
{
|
||||
AOUTHDR standard;
|
||||
|
||||
/* NT extra fields; see internal.h for descriptions */
|
||||
char ImageBase[4];
|
||||
char SectionAlignment[4];
|
||||
char FileAlignment[4];
|
||||
char MajorOperatingSystemVersion[2];
|
||||
char MinorOperatingSystemVersion[2];
|
||||
char MajorImageVersion[2];
|
||||
char MinorImageVersion[2];
|
||||
char MajorSubsystemVersion[2];
|
||||
char MinorSubsystemVersion[2];
|
||||
char Reserved1[4];
|
||||
char SizeOfImage[4];
|
||||
char SizeOfHeaders[4];
|
||||
char CheckSum[4];
|
||||
char Subsystem[2];
|
||||
char DllCharacteristics[2];
|
||||
char SizeOfStackReserve[4];
|
||||
char SizeOfStackCommit[4];
|
||||
char SizeOfHeapReserve[4];
|
||||
char SizeOfHeapCommit[4];
|
||||
char LoaderFlags[4];
|
||||
char NumberOfRvaAndSizes[4];
|
||||
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
|
||||
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
|
||||
} PEAOUTHDR;
|
||||
#endif
|
||||
#undef AOUTSZ
|
||||
#define AOUTSZ (AOUTHDRSZ + 196)
|
||||
|
||||
/* Like PEAOUTHDR, except that the "standard" member has no BaseOfData
|
||||
(aka data_start) member and that some of the members are 8 instead
|
||||
of just 4 bytes long. */
|
||||
#ifndef __ASSEMBLY__
|
||||
typedef struct
|
||||
{
|
||||
AOUTHDR standard;
|
||||
|
||||
/* NT extra fields; see internal.h for descriptions */
|
||||
char ImageBase[8];
|
||||
char SectionAlignment[4];
|
||||
char FileAlignment[4];
|
||||
char MajorOperatingSystemVersion[2];
|
||||
char MinorOperatingSystemVersion[2];
|
||||
char MajorImageVersion[2];
|
||||
char MinorImageVersion[2];
|
||||
char MajorSubsystemVersion[2];
|
||||
char MinorSubsystemVersion[2];
|
||||
char Reserved1[4];
|
||||
char SizeOfImage[4];
|
||||
char SizeOfHeaders[4];
|
||||
char CheckSum[4];
|
||||
char Subsystem[2];
|
||||
char DllCharacteristics[2];
|
||||
char SizeOfStackReserve[8];
|
||||
char SizeOfStackCommit[8];
|
||||
char SizeOfHeapReserve[8];
|
||||
char SizeOfHeapCommit[8];
|
||||
char LoaderFlags[4];
|
||||
char NumberOfRvaAndSizes[4];
|
||||
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
|
||||
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
|
||||
} PEP64AOUTHDR;
|
||||
#endif
|
||||
#define PEP64AOUTSZ 240
|
||||
|
||||
#undef E_FILNMLEN
|
||||
#define E_FILNMLEN 18 /* # characters in a file name */
|
||||
|
||||
/* Import Tyoes fot ILF format object files.. */
|
||||
#define IMPORT_CODE 0
|
||||
#define IMPORT_DATA 1
|
||||
#define IMPORT_CONST 2
|
||||
|
||||
/* Import Name Tyoes for ILF format object files. */
|
||||
#define IMPORT_ORDINAL 0
|
||||
#define IMPORT_NAME 1
|
||||
#define IMPORT_NAME_NOPREFIX 2
|
||||
#define IMPORT_NAME_UNDECORATE 3
|
||||
|
||||
#endif /* _PE_H */
|
2
boot/sbat.csv
Normal file
2
boot/sbat.csv
Normal file
|
@ -0,0 +1,2 @@
|
|||
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
|
||||
memtest86+,1,Memtest86+,6.0,https://github.com/memtest86plus
|
|
|
@ -18,6 +18,7 @@
|
|||
#define __ASSEMBLY__
|
||||
|
||||
#include "boot.h"
|
||||
#include "build_version.h"
|
||||
|
||||
#define BOOT_PARAMS_START (SETUP_SECS * 512)
|
||||
#define BOOT_PARAMS_END (BOOT_PARAMS_START + 4096)
|
||||
|
@ -41,7 +42,7 @@ realmode_swtch:
|
|||
start_sys_seg:
|
||||
.word 0x1000
|
||||
kernel_version:
|
||||
.word 0
|
||||
.word mt86plus_version-512
|
||||
type_of_loader:
|
||||
.byte 0
|
||||
loadflags:
|
||||
|
@ -385,6 +386,10 @@ idt_descr:
|
|||
.word 0 # idt limit=0
|
||||
.long 0 # idt base=0
|
||||
|
||||
mt86plus_version:
|
||||
.ascii "Memtest86+ v" , MT_VERSION
|
||||
.byte 0
|
||||
|
||||
# Pad to the declared size.
|
||||
|
||||
.org (SETUP_SECS*512)
|
||||
|
|
|
@ -812,7 +812,7 @@ startup_stack_top:
|
|||
|
||||
# Main stack area.
|
||||
|
||||
.section "stacks", "aw", @progbits
|
||||
.section ".stacks", "aw", @nobits
|
||||
.align 16
|
||||
|
||||
. = . + STACKS_SIZE
|
||||
|
|
|
@ -75,16 +75,15 @@ all: memtest.bin memtest.efi
|
|||
-include $(subst .o,.d,$(TST_OBJS))
|
||||
-include $(subst .o,.d,$(APP_OBJS))
|
||||
|
||||
boot/%.o: boot/%.s
|
||||
$(AS) $< -o $@
|
||||
boot/header.o : | ../boot/sbat.csv
|
||||
|
||||
boot/startup.s: ../boot/startup32.S ../boot/boot.h
|
||||
boot/startup.o: ../boot/startup32.S ../boot/boot.h
|
||||
@mkdir -p boot
|
||||
$(CC) -m32 -E -traditional -I../boot -o $@ $<
|
||||
$(CC) -m32 -x assembler-with-cpp -c -I../boot -o $@ $<
|
||||
|
||||
boot/%.s: ../boot/%.S ../boot/boot.h
|
||||
boot/%.o: ../boot/%.S ../boot/boot.h app/build_version.h
|
||||
@mkdir -p boot
|
||||
$(CC) -m32 -E -traditional -I../boot -o $@ $<
|
||||
$(CC) -m32 -x assembler-with-cpp -c -I../boot -Iapp -o $@ $<
|
||||
|
||||
boot/efisetup.o: ../boot/efisetup.c
|
||||
@mkdir -p boot
|
||||
|
@ -106,20 +105,22 @@ tests/%.o: ../tests/%.c
|
|||
@mkdir -p tests
|
||||
$(CC) -c $(CFLAGS) -O3 $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
app/%.o: ../app/%.c app/githash.h
|
||||
app/%.o: ../app/%.c app/build_version.h
|
||||
@mkdir -p app
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
app/githash.h: FORCE
|
||||
app/build_version.h: FORCE
|
||||
@mkdir -p app
|
||||
@( \
|
||||
cp -f ../app/version.h $@.tmp; \
|
||||
if $(GIT_AVAILABLE) && test -d ../.git ; then \
|
||||
hash=`git rev-parse HEAD | cut -c1-7`; \
|
||||
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "'$$hash'"/' $@.tmp; \
|
||||
else \
|
||||
hash="unknown"; \
|
||||
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "unknown"/' $@.tmp; \
|
||||
fi; \
|
||||
define=`echo "#define GIT_HASH \"$$hash\""`; \
|
||||
echo $$define | diff - $@ > /dev/null 2>&1 || echo $$define > $@; \
|
||||
cmp $@ $@.tmp 2>/dev/null || cp -f $@.tmp $@; \
|
||||
rm -f $@.tmp; \
|
||||
)
|
||||
|
||||
FORCE:
|
||||
|
@ -169,8 +170,13 @@ iso: memtest.iso
|
|||
clean:
|
||||
rm -rf boot system lib tests app *.img *.iso memtest* iso grub-*
|
||||
|
||||
# grub-memtest.iso can be used for testing the various different boot modes,
|
||||
# using GRUB as an intermediate bootloader. Upstream GRUB only supports the
|
||||
# grub-memtest.iso uses GRUB as an intermediate bootloader to allow Memtest86+
|
||||
# to be started with the native USB keyboard drivers either enabled or disabled,
|
||||
# or to be started in a fail-safe mode with SMP and memory identification &
|
||||
# speed testing disabled.
|
||||
#
|
||||
# By setting GRUB_CFG to "grub-test", grub-memtest.iso can instead be used for
|
||||
# testing the various different boot modes. Upstream GRUB only supports the
|
||||
# 16-bit and 32-bit boot protocols, via the "linux16" and "linux" commands.
|
||||
# Fedora add support for the EFI handover boot protocols, via the "linuxefi"
|
||||
# command, and, since 2019, remove support for the 32-bit protocol, aliasing
|
||||
|
@ -180,6 +186,8 @@ clean:
|
|||
# doubt do their own thing. The boot menu on grub-memtest.iso attempts to
|
||||
# support all these options.
|
||||
|
||||
GRUB_CFG ?= grub
|
||||
|
||||
GRUB_FONT_DIR ?= /usr/share/grub
|
||||
|
||||
GRUB_LIB_DIR ?= /usr/lib/grub
|
||||
|
@ -195,22 +203,22 @@ grub-eltorito.img:
|
|||
grub-bootia32.efi:
|
||||
$(GRUB_MKIMAGE) --output $@ --prefix /EFI/BOOT/grub --format i386-efi $(GRUB_MODULES)
|
||||
|
||||
grub-esp.img: memtest.efi grub-bootia32.efi ../grub/grub-efi.cfg
|
||||
grub-esp.img: memtest.efi grub-bootia32.efi ../grub/${GRUB_CFG}-efi.cfg
|
||||
@mkdir -p grub-iso/EFI/BOOT/grub/i386-efi grub-iso/EFI/BOOT/grub/fonts
|
||||
cp memtest.efi grub-iso/EFI/BOOT/memtest
|
||||
cp grub-bootia32.efi grub-iso/EFI/BOOT/bootia32.efi
|
||||
cp ../grub/grub-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg
|
||||
cp ../grub/${GRUB_CFG}-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg
|
||||
cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/EFI/BOOT/grub/fonts/
|
||||
cp $(GRUB_LIB_DIR)/i386-efi/*.mod grub-iso/EFI/BOOT/grub/i386-efi/
|
||||
@rm -f grub-esp.img
|
||||
/sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192
|
||||
mcopy -s -i grub-esp.img grub-iso/EFI ::
|
||||
|
||||
grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/grub-legacy.cfg grub-esp.img
|
||||
grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/${GRUB_CFG}-legacy.cfg grub-esp.img
|
||||
@mkdir -p grub-iso/boot/grub/i386-pc grub-iso/boot/grub/fonts
|
||||
cp memtest.bin grub-iso/boot/memtest
|
||||
cp grub-eltorito.img grub-iso/boot/eltorito.img
|
||||
cp ../grub/grub-legacy.cfg grub-iso/boot/grub/grub.cfg
|
||||
cp ../grub/${GRUB_CFG}-legacy.cfg grub-iso/boot/grub/grub.cfg
|
||||
cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/boot/grub/fonts/
|
||||
cp $(GRUB_LIB_DIR)/i386-pc/*.mod grub-iso/boot/grub/i386-pc/
|
||||
xorrisofs -pad -R -J -volid MT86PLUS_32 -graft-points -hide-rr-moved \
|
||||
|
|
|
@ -12,15 +12,48 @@ SECTIONS {
|
|||
}
|
||||
. = ALIGN(512);
|
||||
.text : {
|
||||
_text_start = . ;
|
||||
_file_text_start = . ;
|
||||
*(.data)
|
||||
_real_text_end = . ;
|
||||
. = ALIGN(512);
|
||||
_text_end = . ;
|
||||
_file_text_end = . ;
|
||||
}
|
||||
.reloc : {
|
||||
_file_reloc_start = . ;
|
||||
*(.reloc)
|
||||
_real_reloc_end = . ;
|
||||
. = ALIGN(512);
|
||||
_file_reloc_end = . ;
|
||||
}
|
||||
.sbat : {
|
||||
_file_sbat_start = . ;
|
||||
*(.sbat)
|
||||
_real_sbat_end = . ;
|
||||
. = ALIGN(512);
|
||||
_file_sbat_end = . ;
|
||||
}
|
||||
/DISCARD/ : { *(*) }
|
||||
|
||||
_text_size = (_text_end - _text_start);
|
||||
_real_text_size = _real_text_end - _file_text_start;
|
||||
_real_reloc_size = _real_reloc_end - _file_reloc_start;
|
||||
_real_sbat_size = _real_sbat_end - _file_sbat_start;
|
||||
|
||||
_sys_size = _text_size >> 4;
|
||||
_init_size = _text_size + _bss_size;
|
||||
_file_head_size = _file_text_start;
|
||||
_file_text_size = _file_text_end - _file_text_start;
|
||||
_file_reloc_size = _file_reloc_end - _file_reloc_start;
|
||||
_file_sbat_size = _file_sbat_end - _file_sbat_start;
|
||||
|
||||
_sys_size = (_real_text_size + 15) >> 4;
|
||||
_init_size = _real_text_size + _bss_size;
|
||||
|
||||
_virt_head_size = ((_file_head_size + 4095) >> 12) << 12;
|
||||
_virt_text_size = ((_init_size + 4095) >> 12) << 12;
|
||||
_virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12;
|
||||
_virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12;
|
||||
|
||||
_virt_text_start = _virt_head_size;
|
||||
_virt_reloc_start = _virt_text_start + _virt_text_size;
|
||||
_virt_sbat_start = _virt_reloc_start + _virt_reloc_size;
|
||||
|
||||
_virt_img_size = _virt_sbat_start + _virt_sbat_size;
|
||||
}
|
||||
|
|
|
@ -74,16 +74,15 @@ all: memtest.bin memtest.efi
|
|||
-include $(subst .o,.d,$(TST_OBJS))
|
||||
-include $(subst .o,.d,$(APP_OBJS))
|
||||
|
||||
boot/%.o: boot/%.s
|
||||
$(AS) $< -o $@
|
||||
boot/header.o : | ../boot/sbat.csv
|
||||
|
||||
boot/startup.s: ../boot/startup64.S ../boot/boot.h
|
||||
boot/startup.o: ../boot/startup64.S ../boot/boot.h
|
||||
@mkdir -p boot
|
||||
$(CC) -E -traditional -I../boot -o $@ $<
|
||||
$(CC) -m64 -x assembler-with-cpp -c -I../boot -o $@ $<
|
||||
|
||||
boot/%.s: ../boot/%.S ../boot/boot.h
|
||||
boot/%.o: ../boot/%.S ../boot/boot.h app/build_version.h
|
||||
@mkdir -p boot
|
||||
$(CC) -E -traditional -I../boot -o $@ $<
|
||||
$(CC) -m64 -x assembler-with-cpp -c -I../boot -Iapp -o $@ $<
|
||||
|
||||
boot/efisetup.o: ../boot/efisetup.c
|
||||
@mkdir -p boot
|
||||
|
@ -105,20 +104,22 @@ tests/%.o: ../tests/%.c
|
|||
@mkdir -p tests
|
||||
$(CC) -c $(CFLAGS) -O3 $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
app/%.o: ../app/%.c app/githash.h
|
||||
app/%.o: ../app/%.c app/build_version.h
|
||||
@mkdir -p app
|
||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
||||
|
||||
app/githash.h: FORCE
|
||||
app/build_version.h: FORCE
|
||||
@mkdir -p app
|
||||
@( \
|
||||
cp -f ../app/version.h $@.tmp; \
|
||||
if $(GIT_AVAILABLE) && test -d ../.git ; then \
|
||||
hash=`git rev-parse HEAD | cut -c1-7`; \
|
||||
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "'$$hash'"/' $@.tmp; \
|
||||
else \
|
||||
hash="unknown"; \
|
||||
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "unknown"/' $@.tmp; \
|
||||
fi; \
|
||||
define=`echo "#define GIT_HASH \"$$hash\""`; \
|
||||
echo $$define | diff - $@ > /dev/null 2>&1 || echo $$define > $@; \
|
||||
cmp $@ $@.tmp 2>/dev/null || cp -f $@.tmp $@; \
|
||||
rm -f $@.tmp; \
|
||||
)
|
||||
|
||||
FORCE:
|
||||
|
@ -168,8 +169,13 @@ iso: memtest.iso
|
|||
clean:
|
||||
rm -rf boot system lib tests app *.img *.iso memtest* iso grub-*
|
||||
|
||||
# grub-memtest.iso can be used for testing the various different boot modes,
|
||||
# using GRUB as an intermediate bootloader. Upstream GRUB only supports the
|
||||
# grub-memtest.iso uses GRUB as an intermediate bootloader to allow Memtest86+
|
||||
# to be started with the native USB keyboard drivers either enabled or disabled,
|
||||
# or to be started in a fail-safe mode with SMP and memory identification &
|
||||
# speed testing disabled.
|
||||
#
|
||||
# By setting GRUB_CFG to "grub-test", grub-memtest.iso can instead be used for
|
||||
# testing the various different boot modes. Upstream GRUB only supports the
|
||||
# 16-bit and 32-bit boot protocols, via the "linux16" and "linux" commands.
|
||||
# Fedora add support for the EFI handover boot protocols, via the "linuxefi"
|
||||
# command, and, since 2019, remove support for the 32-bit protocol, aliasing
|
||||
|
@ -179,6 +185,8 @@ clean:
|
|||
# doubt do their own thing. The boot menu on grub-memtest.iso attempts to
|
||||
# support all these options.
|
||||
|
||||
GRUB_CFG ?= grub
|
||||
|
||||
GRUB_FONT_DIR ?= /usr/share/grub
|
||||
|
||||
GRUB_LIB_DIR ?= /usr/lib/grub
|
||||
|
@ -194,22 +202,22 @@ grub-eltorito.img:
|
|||
grub-bootx64.efi:
|
||||
$(GRUB_MKIMAGE) --output $@ --prefix /EFI/BOOT/grub --format x86_64-efi $(GRUB_MODULES)
|
||||
|
||||
grub-esp.img: memtest.efi grub-bootx64.efi ../grub/grub-efi.cfg
|
||||
grub-esp.img: memtest.efi grub-bootx64.efi ../grub/${GRUB_CFG}-efi.cfg
|
||||
@mkdir -p grub-iso/EFI/BOOT/grub/x86_64-efi grub-iso/EFI/BOOT/grub/fonts
|
||||
cp memtest.efi grub-iso/EFI/BOOT/memtest
|
||||
cp grub-bootx64.efi grub-iso/EFI/BOOT/bootx64.efi
|
||||
cp ../grub/grub-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg
|
||||
cp ../grub/${GRUB_CFG}-efi.cfg grub-iso/EFI/BOOT/grub/grub.cfg
|
||||
cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/EFI/BOOT/grub/fonts/
|
||||
cp $(GRUB_LIB_DIR)/x86_64-efi/*.mod grub-iso/EFI/BOOT/grub/x86_64-efi/
|
||||
@rm -f grub-esp.img
|
||||
/sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192
|
||||
mcopy -s -i grub-esp.img grub-iso/EFI ::
|
||||
|
||||
grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/grub-legacy.cfg grub-esp.img
|
||||
grub-memtest.iso: memtest.bin grub-eltorito.img ../grub/${GRUB_CFG}-legacy.cfg grub-esp.img
|
||||
@mkdir -p grub-iso/boot/grub/i386-pc grub-iso/boot/grub/fonts
|
||||
cp memtest.bin grub-iso/boot/memtest
|
||||
cp grub-eltorito.img grub-iso/boot/eltorito.img
|
||||
cp ../grub/grub-legacy.cfg grub-iso/boot/grub/grub.cfg
|
||||
cp ../grub/${GRUB_CFG}-legacy.cfg grub-iso/boot/grub/grub.cfg
|
||||
cp $(GRUB_FONT_DIR)/unicode.pf2 grub-iso/boot/grub/fonts/
|
||||
cp $(GRUB_LIB_DIR)/i386-pc/*.mod grub-iso/boot/grub/i386-pc/
|
||||
xorrisofs -pad -R -J -volid MT86PLUS_64 -graft-points -hide-rr-moved \
|
||||
|
|
|
@ -12,15 +12,48 @@ SECTIONS {
|
|||
}
|
||||
. = ALIGN(512);
|
||||
.text : {
|
||||
_text_start = . ;
|
||||
_file_text_start = . ;
|
||||
*(.data)
|
||||
_real_text_end = . ;
|
||||
. = ALIGN(512);
|
||||
_text_end = . ;
|
||||
_file_text_end = . ;
|
||||
}
|
||||
.reloc : {
|
||||
_file_reloc_start = . ;
|
||||
*(.reloc)
|
||||
_real_reloc_end = . ;
|
||||
. = ALIGN(512);
|
||||
_file_reloc_end = . ;
|
||||
}
|
||||
.sbat : {
|
||||
_file_sbat_start = . ;
|
||||
*(.sbat)
|
||||
_real_sbat_end = . ;
|
||||
. = ALIGN(512);
|
||||
_file_sbat_end = . ;
|
||||
}
|
||||
/DISCARD/ : { *(*) }
|
||||
|
||||
_text_size = (_text_end - _text_start);
|
||||
_real_text_size = _real_text_end - _file_text_start;
|
||||
_real_reloc_size = _real_reloc_end - _file_reloc_start;
|
||||
_real_sbat_size = _real_sbat_end - _file_sbat_start;
|
||||
|
||||
_sys_size = _text_size >> 4;
|
||||
_init_size = _text_size + _bss_size;
|
||||
_file_head_size = _file_text_start;
|
||||
_file_text_size = _file_text_end - _file_text_start;
|
||||
_file_reloc_size = _file_reloc_end - _file_reloc_start;
|
||||
_file_sbat_size = _file_sbat_end - _file_sbat_start;
|
||||
|
||||
_sys_size = (_real_text_size + 15) >> 4;
|
||||
_init_size = _real_text_size + _bss_size;
|
||||
|
||||
_virt_head_size = ((_file_head_size + 4095) >> 12) << 12;
|
||||
_virt_text_size = ((_init_size + 4095) >> 12) << 12;
|
||||
_virt_reloc_size = ((_file_reloc_size + 4095) >> 12) << 12;
|
||||
_virt_sbat_size = ((_file_sbat_size + 4095) >> 12) << 12;
|
||||
|
||||
_virt_text_start = _virt_head_size;
|
||||
_virt_reloc_start = _virt_text_start + _virt_text_size;
|
||||
_virt_sbat_start = _virt_reloc_start + _virt_reloc_size;
|
||||
|
||||
_virt_img_size = _virt_sbat_start + _virt_sbat_size;
|
||||
}
|
||||
|
|
|
@ -8,15 +8,13 @@ set default=0
|
|||
set timeout=-1
|
||||
|
||||
insmod linux
|
||||
insmod linuxefi
|
||||
insmod linux32
|
||||
|
||||
menuentry "Start Memtest86+ using 'linux' command" {
|
||||
linux /EFI/BOOT/memtest
|
||||
menuentry "Start Memtest86+, use built-in support for USB keyboards" {
|
||||
linux /EFI/BOOT/memtest keyboard=both
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linuxefi' command" {
|
||||
linuxefi /EFI/BOOT/memtest
|
||||
menuentry "Start Memtest86+, use BIOS legacy emulation for USB keyboards" {
|
||||
linux /EFI/BOOT/memtest keyboard=legacy
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linux32' command" {
|
||||
linux32 /EFI/BOOT/memtest
|
||||
menuentry "Start Memtest86+, disable SMP and memory identification" {
|
||||
linux /EFI/BOOT/memtest nosmp nosm nobench
|
||||
}
|
||||
|
|
|
@ -8,15 +8,13 @@ set default=0
|
|||
set timeout=-1
|
||||
|
||||
insmod linux
|
||||
insmod linux16
|
||||
insmod linux32
|
||||
|
||||
menuentry "Start Memtest86+ using 'linux' command" {
|
||||
linux /boot/memtest
|
||||
menuentry "Start Memtest86+, use built-in support for USB keyboards" {
|
||||
linux /boot/memtest keyboard=both
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linux16' command" {
|
||||
linux16 /boot/memtest
|
||||
menuentry "Start Memtest86+, use BIOS legacy emulation for USB keyboards" {
|
||||
linux /boot/memtest keyboard=legacy
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linux32' command" {
|
||||
linux32 /boot/memtest
|
||||
menuentry "Start Memtest86+, disable SMP and memory identification" {
|
||||
linux /boot/memtest nosmp nosm nobench
|
||||
}
|
||||
|
|
22
grub/grub-test-efi.cfg
Normal file
22
grub/grub-test-efi.cfg
Normal file
|
@ -0,0 +1,22 @@
|
|||
if loadfont unicode ; then
|
||||
set gfxmode=1024x768,800x600,auto
|
||||
set gfxpayload=800x600,1024x768
|
||||
terminal_output gfxterm
|
||||
fi
|
||||
|
||||
set default=0
|
||||
set timeout=-1
|
||||
|
||||
insmod linux
|
||||
insmod linuxefi
|
||||
insmod linux32
|
||||
|
||||
menuentry "Start Memtest86+ using 'linux' command" {
|
||||
linux /EFI/BOOT/memtest
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linuxefi' command" {
|
||||
linuxefi /EFI/BOOT/memtest
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linux32' command" {
|
||||
linux32 /EFI/BOOT/memtest
|
||||
}
|
22
grub/grub-test-legacy.cfg
Normal file
22
grub/grub-test-legacy.cfg
Normal file
|
@ -0,0 +1,22 @@
|
|||
if loadfont unicode ; then
|
||||
set gfxmode=1024x768,800x600,auto
|
||||
set gfxpayload=800x600,1024x768
|
||||
terminal_output gfxterm
|
||||
fi
|
||||
|
||||
set default=0
|
||||
set timeout=-1
|
||||
|
||||
insmod linux
|
||||
insmod linux16
|
||||
insmod linux32
|
||||
|
||||
menuentry "Start Memtest86+ using 'linux' command" {
|
||||
linux /boot/memtest
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linux16' command" {
|
||||
linux16 /boot/memtest
|
||||
}
|
||||
menuentry "Start Memtest86+ using 'linux32' command" {
|
||||
linux32 /boot/memtest
|
||||
}
|
34
lib/string.c
34
lib/string.c
|
@ -31,18 +31,6 @@ void reverse(char s[])
|
|||
// Public Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
const unsigned char *src1 = s1, *src2 = s2;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (src1[i] != src2[i]) {
|
||||
return (int)src1[i] - (int)src2[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
char *d = (char *)dest, *s = (char *)src;
|
||||
|
@ -64,28 +52,6 @@ void *memmove(void *dest, const void *src, size_t n)
|
|||
return dest;
|
||||
}
|
||||
|
||||
size_t strlen(const char *s)
|
||||
{
|
||||
size_t len = 0;
|
||||
while (*s++) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (s1[i] != s2[i]) {
|
||||
return (int)s1[i] - (int)s2[i];
|
||||
}
|
||||
if (s1[i] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strstr(const char *haystack, const char *needle)
|
||||
{
|
||||
size_t haystack_len = strlen(haystack);
|
||||
|
|
34
lib/string.h
34
lib/string.h
|
@ -18,7 +18,17 @@
|
|||
* between the first mismatching byte in s1 (interpreted as an unsigned
|
||||
* value) and the corresponding byte in s2.
|
||||
*/
|
||||
int memcmp(const void *s1, const void *s2, size_t n);
|
||||
static inline int memcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
const unsigned char *src1 = s1, *src2 = s2;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (src1[i] != src2[i]) {
|
||||
return (int)src1[i] - (int)src2[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies n bytes from the memory area pointed to by src to the memory area
|
||||
|
@ -45,7 +55,14 @@ void *memmove(void *dest, const void *src, size_t n);
|
|||
/**
|
||||
* Returns the string length, excluding the terminating null character.
|
||||
*/
|
||||
size_t strlen(const char *s);
|
||||
static inline size_t strlen(const char *s)
|
||||
{
|
||||
size_t len = 0;
|
||||
while (*s++) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares at most the first n characters in the strings s1 and s2 and
|
||||
|
@ -53,7 +70,18 @@ size_t strlen(const char *s);
|
|||
* between the first mismatching character in s1 (interpreted as a signed
|
||||
* value) and the corresponding character in s2.
|
||||
*/
|
||||
int strncmp(const char *s1, const char *s2, size_t n);
|
||||
static inline int strncmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (s1[i] != s2[i]) {
|
||||
return (int)s1[i] - (int)s2[i];
|
||||
}
|
||||
if (s1[i] == '\0') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first occurrence of the substring needle in the string haystack
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Derived from memtest86+ cpuid.h
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpuid.h"
|
||||
|
@ -36,7 +36,7 @@ void cpuid_init(void)
|
|||
// Get the processor family information & feature flags.
|
||||
if (cpuid_info.max_cpuid >= 1) {
|
||||
cpuid(0x1, 0,
|
||||
&cpuid_info.version.raw,
|
||||
&cpuid_info.version.raw[0],
|
||||
&cpuid_info.proc_info.raw,
|
||||
&cpuid_info.flags.raw[1],
|
||||
&cpuid_info.flags.raw[0]
|
||||
|
@ -65,8 +65,8 @@ void cpuid_init(void)
|
|||
if (cpuid_info.max_xcpuid >= 0x80000001) {
|
||||
cpuid(0x80000001, 0,
|
||||
®[0],
|
||||
&cpuid_info.version.raw[1],
|
||||
®[1],
|
||||
®[2],
|
||||
&cpuid_info.flags.raw[2]
|
||||
);
|
||||
}
|
||||
|
@ -108,30 +108,21 @@ void cpuid_init(void)
|
|||
}
|
||||
|
||||
// Get cache information.
|
||||
switch (cpuid_info.vendor_id.str[0]) {
|
||||
case 'A':
|
||||
// AMD Processors
|
||||
if (cpuid_info.max_xcpuid >= 0x80000005) {
|
||||
cpuid(0x80000005, 0,
|
||||
®[0],
|
||||
®[1],
|
||||
&cpuid_info.cache_info.raw[0],
|
||||
&cpuid_info.cache_info.raw[1]
|
||||
);
|
||||
}
|
||||
if (cpuid_info.max_xcpuid >= 0x80000006) {
|
||||
cpuid(0x80000006, 0,
|
||||
®[0],
|
||||
®[1],
|
||||
&cpuid_info.cache_info.raw[2],
|
||||
&cpuid_info.cache_info.raw[3]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
// Intel Processors
|
||||
// No cpuid info to read.
|
||||
break;
|
||||
if (cpuid_info.max_xcpuid >= 0x80000005) {
|
||||
cpuid(0x80000005, 0,
|
||||
®[0],
|
||||
®[1],
|
||||
&cpuid_info.cache_info.raw[0],
|
||||
&cpuid_info.cache_info.raw[1]
|
||||
);
|
||||
}
|
||||
if (cpuid_info.max_xcpuid >= 0x80000006) {
|
||||
cpuid(0x80000006, 0,
|
||||
®[0],
|
||||
®[1],
|
||||
&cpuid_info.cache_info.raw[2],
|
||||
&cpuid_info.cache_info.raw[3]
|
||||
);
|
||||
}
|
||||
|
||||
// Detect CPU Topology (Core/Thread) infos
|
||||
|
@ -176,12 +167,17 @@ void cpuid_init(void)
|
|||
}
|
||||
break;
|
||||
case 'C':
|
||||
// VIA / CentaurHauls
|
||||
// Cyrix / VIA / CentaurHauls / Zhaoxin
|
||||
cpuid_info.flags.htt = false;
|
||||
break;
|
||||
case 'G':
|
||||
if (cpuid_info.vendor_id.str[7] == 'T') break; // Transmeta
|
||||
// Intel
|
||||
if (cpuid_info.max_cpuid >= 0xB) {
|
||||
cpuid(0xB, 0, ®[0], ®[1], ®[2], ®[3]);
|
||||
}
|
||||
|
||||
if (cpuid_info.max_cpuid >= 0xB && (reg[1] & 0xFF) != 0) { // Check if Extended Topology Information is available
|
||||
|
||||
// Populate Hybrid Status (CPUID 7.EDX[15]) for Alder Lake+
|
||||
cpuid(0x7, 0, ®[0], ®[1], ®[2], ®[3]);
|
||||
|
@ -191,7 +187,7 @@ void cpuid_init(void)
|
|||
cpuid_info.topology.ecore_count = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i < 4; i++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
cpuid(0xB, i, ®[0], ®[1], ®[2], ®[3]);
|
||||
|
||||
switch((reg[2] >> 8) & 0xFF) {
|
||||
|
@ -215,7 +211,11 @@ void cpuid_init(void)
|
|||
cpuid_info.topology.thread_count = cpuid_info.topology.core_count;
|
||||
|
||||
if (cpuid_info.flags.htt){
|
||||
cpuid_info.topology.thread_count *= 2;
|
||||
if (((cpuid_info.proc_info.raw >> 16) & 0xFF) > (uint32_t)cpuid_info.topology.core_count) {
|
||||
cpuid_info.topology.thread_count *= 2;
|
||||
} else {
|
||||
cpuid_info.flags.htt = !cpuid_info.flags.htt;
|
||||
}
|
||||
}
|
||||
} else if (cpuid_info.max_cpuid >= 0x2) {
|
||||
if(cpuid_info.flags.htt){
|
||||
|
|
|
@ -29,7 +29,7 @@ typedef enum {
|
|||
*/
|
||||
|
||||
typedef union {
|
||||
uint32_t raw;
|
||||
uint32_t raw[2];
|
||||
struct {
|
||||
uint32_t stepping : 4;
|
||||
uint32_t model : 4;
|
||||
|
@ -39,6 +39,7 @@ typedef union {
|
|||
uint32_t extendedModel : 4;
|
||||
uint32_t extendedFamily : 8;
|
||||
uint32_t : 4;
|
||||
uint32_t extendedBrandID : 32; // AMD Only
|
||||
};
|
||||
} cpuid_version_t;
|
||||
|
||||
|
@ -122,7 +123,7 @@ typedef union {
|
|||
} cpuid_brand_string_t;
|
||||
|
||||
typedef union {
|
||||
uint32_t raw[12];
|
||||
uint32_t raw[4];
|
||||
struct {
|
||||
uint32_t : 24;
|
||||
uint32_t l1_i_size : 8;
|
||||
|
|
168
system/cpuinfo.c
168
system/cpuinfo.c
|
@ -71,12 +71,45 @@ static void determine_cache_size()
|
|||
l3_cache *= 512;
|
||||
break;
|
||||
case 'C':
|
||||
// Zhaoxin CPU only
|
||||
if (cpuid_info.version.family != 7) {
|
||||
if (cpuid_info.vendor_id.str[5] == 'I') {
|
||||
// Cyrix
|
||||
if (cpuid_info.version.family == 5 && cpuid_info.version.model == 4) {
|
||||
// Media GXm, Geode GXm/GXLV/GX1
|
||||
// Cache info in CPUID has a Cyrix-specific encoding so hardcode it
|
||||
l1_cache = 16;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// WinChip 2/3, VIA C3/C7/Nano
|
||||
if (cpuid_info.version.family == 5 || cpuid_info.version.family == 6) {
|
||||
l1_cache = cpuid_info.cache_info.l1_d_size;
|
||||
l2_cache = cpuid_info.cache_info.l2_size;
|
||||
break;
|
||||
} else if (cpuid_info.version.family != 7) {
|
||||
break;
|
||||
}
|
||||
// Zhaoxin CPU only
|
||||
/* fall through */
|
||||
case 'G':
|
||||
if (cpuid_info.vendor_id.str[9] == 'N') {
|
||||
// National Semiconductor
|
||||
if (cpuid_info.version.family == 5) {
|
||||
switch (cpuid_info.version.model) {
|
||||
case 4:
|
||||
// Geode GXm/GXLV/GX1
|
||||
// Cache info in CPUID has a Cyrix-specific encoding so hardcode it
|
||||
l1_cache = 16;
|
||||
break;
|
||||
case 5:
|
||||
// Geode GX2
|
||||
l1_cache = cpuid_info.cache_info.l1_d_size;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Intel Processors
|
||||
l1_cache = 0;
|
||||
l2_cache = 0;
|
||||
|
@ -296,10 +329,12 @@ static void determine_imc(void)
|
|||
imc_type = IMC_K18; // Hygon (Family 18h)
|
||||
break;
|
||||
case 0xA:
|
||||
if(cpuid_info.version.extendedModel == 5) {
|
||||
if (cpuid_info.version.extendedModel == 5) {
|
||||
imc_type = IMC_K19_CZN; // AMD Cezanne APU (Model 0x50-5F - Family 19h)
|
||||
} else if (cpuid_info.version.extendedModel >= 6) {
|
||||
imc_type = IMC_K19_RPL; // Zen4 (Family 19h)
|
||||
} else {
|
||||
imc_type = IMC_K19; // Zen3 & Zen4 (Family 19h)
|
||||
imc_type = IMC_K19; // Zen3 (Family 19h)
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
@ -458,6 +493,9 @@ static void determine_imc(void)
|
|||
case 0x9:
|
||||
imc_type = IMC_KBL; // Core 7/8/9th Gen (Kaby/Coffee/Comet Lake)
|
||||
break;
|
||||
case 0xB:
|
||||
imc_type = IMC_ADL_N; // Core 12th Gen (Alder Lake-N - Gracemont E-Cores only)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -597,9 +635,9 @@ static void determine_cpu_model(void)
|
|||
// Transmeta Processors - vendor_id starts with "GenuineTMx86"
|
||||
if (cpuid_info.vendor_id.str[7] == 'T' ) {
|
||||
if (cpuid_info.version.family == 5) {
|
||||
cpu_model = "TM 5x00";
|
||||
cpu_model = "Transmeta TM 5x00";
|
||||
} else if (cpuid_info.version.family == 15) {
|
||||
cpu_model = "TM 8x00";
|
||||
cpu_model = "Transmeta TM 8x00";
|
||||
}
|
||||
l1_cache = cpuid_info.cache_info.l1_i_size + cpuid_info.cache_info.l1_d_size;
|
||||
l2_cache = cpuid_info.cache_info.l2_size;
|
||||
|
@ -645,14 +683,14 @@ static void determine_cpu_model(void)
|
|||
case 2:
|
||||
case 3:
|
||||
case 7:
|
||||
cpu_model = "Pentium";
|
||||
cpu_model = "Intel Pentium";
|
||||
if (l1_cache == 0) {
|
||||
l1_cache = 8;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 8:
|
||||
cpu_model = "Pentium-MMX";
|
||||
cpu_model = "Intel Pentium MMX";
|
||||
if (l1_cache == 0) {
|
||||
l1_cache = 16;
|
||||
}
|
||||
|
@ -665,54 +703,54 @@ static void determine_cpu_model(void)
|
|||
switch (cpuid_info.version.model) {
|
||||
case 0:
|
||||
case 1:
|
||||
cpu_model = "Pentium Pro";
|
||||
cpu_model = "Intel Pentium Pro";
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
cpu_model = "Pentium II";
|
||||
cpu_model = "Intel Pentium II";
|
||||
break;
|
||||
case 5:
|
||||
if (l2_cache == 0) {
|
||||
cpu_model = "Celeron";
|
||||
cpu_model = "Intel Celeron";
|
||||
} else {
|
||||
cpu_model = "Pentium II";
|
||||
cpu_model = "Intel Pentium II";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (l2_cache == 128) {
|
||||
cpu_model = "Celeron";
|
||||
cpu_model = "Intel Celeron";
|
||||
} else {
|
||||
cpu_model = "Pentium II";
|
||||
cpu_model = "Intel Pentium II";
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
case 11:
|
||||
if (l2_cache == 128) {
|
||||
cpu_model = "Celeron";
|
||||
cpu_model = "Intel Celeron";
|
||||
} else {
|
||||
cpu_model = "Pentium III";
|
||||
cpu_model = "Intel Pentium III";
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
if (l2_cache == 512) {
|
||||
cpu_model = "Celeron M (0.13)";
|
||||
cpu_model = "Intel Celeron M (0.13)";
|
||||
} else {
|
||||
cpu_model = "Pentium M (0.13)";
|
||||
cpu_model = "Intel Pentium M (0.13)";
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
cpu_model = "Pentium III Xeon";
|
||||
cpu_model = "Intel Pentium III Xeon";
|
||||
break;
|
||||
case 12:
|
||||
l1_cache = 24;
|
||||
cpu_model = "Atom (0.045)";
|
||||
cpu_model = "Intel Atom (0.045)";
|
||||
break;
|
||||
case 13:
|
||||
if (l2_cache == 1024) {
|
||||
cpu_model = "Celeron M (0.09)";
|
||||
cpu_model = "Intel Celeron M (0.09)";
|
||||
} else {
|
||||
cpu_model = "Pentium M (0.09)";
|
||||
cpu_model = "Intel Pentium M (0.09)";
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
|
@ -720,7 +758,7 @@ static void determine_cpu_model(void)
|
|||
break;
|
||||
case 15:
|
||||
if (l2_cache == 1024) {
|
||||
cpu_model = "Pentium E";
|
||||
cpu_model = "Intel Pentium E";
|
||||
} else {
|
||||
cpu_model = "Intel Core 2";
|
||||
}
|
||||
|
@ -735,17 +773,17 @@ static void determine_cpu_model(void)
|
|||
case 1:
|
||||
case 2:
|
||||
if (l2_cache == 128) {
|
||||
cpu_model = "Celeron";
|
||||
cpu_model = "Intel Celeron";
|
||||
} else {
|
||||
cpu_model = "Pentium 4";
|
||||
cpu_model = "Intel Pentium 4";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
if (l2_cache == 256) {
|
||||
cpu_model = "Celeron (0.09)";
|
||||
cpu_model = "Intel Celeron (0.09)";
|
||||
} else {
|
||||
cpu_model = "Pentium 4 (0.09)";
|
||||
cpu_model = "Intel Pentium 4 (0.09)";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
|
@ -765,78 +803,40 @@ static void determine_cpu_model(void)
|
|||
// VIA/Cyrix/Centaur Processors with CPUID
|
||||
if (cpuid_info.vendor_id.str[1] == 'e' ) {
|
||||
// CentaurHauls
|
||||
l1_cache = cpuid_info.cache_info.l1_i_size + cpuid_info.cache_info.l1_d_size;
|
||||
l2_cache = cpuid_info.cache_info.l2_size >> 8;
|
||||
switch (cpuid_info.version.family) {
|
||||
case 5:
|
||||
cpu_model = "Centaur 5x86";
|
||||
cpu_model = "IDT WinChip C6";
|
||||
l1_cache = 32;
|
||||
// WinChip 2/3 (models 8/9) have brand string
|
||||
break;
|
||||
case 6: // VIA C3
|
||||
switch (cpuid_info.version.model) {
|
||||
case 10:
|
||||
cpu_model = "VIA C7 (C5J)";
|
||||
l1_cache = 64;
|
||||
l2_cache = 128;
|
||||
break;
|
||||
case 13:
|
||||
cpu_model = "VIA C7 (C5R)";
|
||||
l1_cache = 64;
|
||||
l2_cache = 128;
|
||||
break;
|
||||
case 15:
|
||||
cpu_model = "VIA Isaiah (CN)";
|
||||
l1_cache = 64;
|
||||
l2_cache = 128;
|
||||
break;
|
||||
default:
|
||||
if (cpuid_info.version.stepping < 8) {
|
||||
cpu_model = "VIA C3 Samuel2";
|
||||
} else {
|
||||
cpu_model = "VIA C3 Eden";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// All VIA/Centaur family values >= 6 have brand string
|
||||
break;
|
||||
}
|
||||
} else { /* CyrixInstead */
|
||||
switch (cpuid_info.version.family) {
|
||||
case 5:
|
||||
case 4:
|
||||
switch (cpuid_info.version.model) {
|
||||
case 0:
|
||||
cpu_model = "Cyrix 6x86MX/MII";
|
||||
case 2:
|
||||
cpu_model = "Cyrix 5x86";
|
||||
l1_cache = 16;
|
||||
break;
|
||||
case 4:
|
||||
cpu_model = "Cyrix GXm";
|
||||
cpu_model = "Cyrix MediaGX/GXi";
|
||||
l1_cache = 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6: // VIA C3
|
||||
switch (cpuid_info.version.model) {
|
||||
case 6:
|
||||
cpu_model = "Cyrix III";
|
||||
break;
|
||||
case 7:
|
||||
if (cpuid_info.version.stepping < 8) {
|
||||
cpu_model = "VIA C3 Samuel2";
|
||||
} else {
|
||||
cpu_model = "VIA C3 Ezra-T";
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
cpu_model = "VIA C3 Ezra-T";
|
||||
break;
|
||||
case 9:
|
||||
cpu_model = "VIA C3 Nehemiah";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// L1 = L2 = 64 KB from Cyrix III to Nehemiah
|
||||
case 5:
|
||||
cpu_model = "Cyrix 6x86/6x86L";
|
||||
l1_cache = 16;
|
||||
// Media GXm (model 4) has brand string
|
||||
break;
|
||||
case 6:
|
||||
cpu_model = "Cyrix 6x86MX/MII";
|
||||
l1_cache = 64;
|
||||
l2_cache = 64;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -847,10 +847,10 @@ static void determine_cpu_model(void)
|
|||
// Unknown processor - make a guess at the family.
|
||||
switch (cpuid_info.version.family) {
|
||||
case 5:
|
||||
cpu_model = "586";
|
||||
cpu_model = "586-class CPU (unknown)";
|
||||
break;
|
||||
case 6:
|
||||
cpu_model = "686";
|
||||
cpu_model = "686-class CPU (unknown)";
|
||||
break;
|
||||
default:
|
||||
cpu_model = "Unidentified Processor";
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*//*
|
||||
* Copyright (C) 2020-2022 Martin Whitaker.
|
||||
* Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||
* Copyright (C) 2004-2023 Sam Demeulemeester.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
@ -47,6 +47,7 @@
|
|||
#define IMC_KBL_UY 0x3030 // Core 7/8/9th Gen (Kaby/Coffee/Comet/Amber Lake-U/Y)
|
||||
#define IMC_ICL 0x3040 // Core 10th Gen (IceLake-Y)
|
||||
#define IMC_TGL 0x3050 // Core 11th Gen (Tiger Lake-U)
|
||||
#define IMC_ADL_N 0x3061 // Core 12th Gen (Alder Lake-N - Gracemont E-Cores only)
|
||||
|
||||
#define IMC_BYT 0x4010 // Atom Bay Trail
|
||||
#define IMC_CDT 0x4020 // Atom Cedar Trail
|
||||
|
@ -59,8 +60,9 @@
|
|||
#define IMC_K16 0x8050 // Kabini & related (Family 16h)
|
||||
#define IMC_K17 0x8060 // Zen & Zen2 (Family 17h)
|
||||
#define IMC_K18 0x8070 // Hygon (Family 18h)
|
||||
#define IMC_K19 0x8080 // Zen3 & Zen4(Family 19h)
|
||||
#define IMC_K19 0x8080 // Zen3 (Family 19h)
|
||||
#define IMC_K19_CZN 0x8081 // Cezanne APU
|
||||
#define IMC_K19_RPL 0x8091 // Zen4 (Family 19h)
|
||||
|
||||
/**
|
||||
* A string identifying the CPU make and model.
|
||||
|
|
|
@ -405,10 +405,9 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_
|
|||
usb_speed_t device_speed, int device_id, usb_ep_t *ep0)
|
||||
{
|
||||
// Store the extra information needed by build_ehci_qhd().
|
||||
ep0->driver_data = port_num << 8;
|
||||
if (hub->level > 0) {
|
||||
ep0->driver_data |= hub->ep0->device_id;
|
||||
}
|
||||
usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed);
|
||||
ep0->driver_data = hs_parent.port_num << 8 | hs_parent.device_id;
|
||||
|
||||
if (!assign_usb_address(hcd, hub, port_num, device_speed, device_id, ep0)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -487,7 +486,7 @@ static const hcd_methods_t methods = {
|
|||
// Public Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
||||
bool ehci_reset(int bus, int dev, int func, uintptr_t base_addr)
|
||||
{
|
||||
ehci_cap_regs_t *cap_regs = (ehci_cap_regs_t *)base_addr;
|
||||
|
||||
|
@ -514,12 +513,21 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
if (!halt_host_controller(op_regs)) return false;
|
||||
if (!reset_host_controller(op_regs)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ehci_probe(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||
{
|
||||
ehci_cap_regs_t *cap_regs = (ehci_cap_regs_t *)base_addr;
|
||||
|
||||
ehci_op_regs_t *op_regs = (ehci_op_regs_t *)(base_addr + cap_regs->cap_length);
|
||||
|
||||
// Record the heap state to allow us to free memory.
|
||||
uintptr_t initial_heap_mark = lm_heap_mark();
|
||||
uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||
|
||||
// Allocate and initialise a periodic frame list. This needs to be aligned on a 4K page boundary. Some controllers
|
||||
// don't support a programmable list length, so we just use the default length.
|
||||
uintptr_t pfl_addr = lm_heap_alloc(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
|
||||
uintptr_t pfl_addr = heap_alloc(HEAP_TYPE_LM_1, EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
|
||||
if (pfl_addr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -530,7 +538,7 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
}
|
||||
|
||||
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
|
||||
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||
if (workspace_addr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -558,9 +566,8 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
|
||||
// Construct a hub descriptor for the root hub.
|
||||
usb_hub_t root_hub;
|
||||
memset(&root_hub, 0, sizeof(root_hub));
|
||||
root_hub.ep0 = NULL;
|
||||
root_hub.level = 0;
|
||||
root_hub.route = 0;
|
||||
root_hub.num_ports = num_ehci_ports(hcs_params);
|
||||
root_hub.power_up_delay = 10; // 20ms
|
||||
|
||||
|
@ -647,7 +654,6 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
|
||||
if (num_keyboards == 0) {
|
||||
(void)halt_host_controller(op_regs);
|
||||
(void)reset_host_controller(op_regs);
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
||||
|
@ -684,6 +690,6 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
return true;
|
||||
|
||||
no_keyboards_found:
|
||||
lm_heap_rewind(initial_heap_mark);
|
||||
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,12 +15,35 @@
|
|||
#include "usbhcd.h"
|
||||
|
||||
/**
|
||||
* Initialises the EHCI device identified by bus, dev, func, and base_addr,
|
||||
* scans all the attached USB devices, and configures any HID USB keyboard
|
||||
* devices it finds to generate periodic interrupt transfers that report key
|
||||
* presses. Initialises hcd and returns true if the device was successfully
|
||||
* initialised and one or more keyboards were found.
|
||||
* If necessary, takes ownership of the EHCI device at the specified base
|
||||
* address, then resets it.
|
||||
*
|
||||
* \param bus - the PCI bus number for accessing the device
|
||||
* \param dev - the PCI device number for accessing the device
|
||||
* \param func - the PCI function number for accessing the device
|
||||
* \param base_addr - the base address of the device in virtual memory
|
||||
*
|
||||
* \returns
|
||||
* true if ownership was acquired and the device was successfully reset,
|
||||
* otherwise false.
|
||||
*/
|
||||
bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd);
|
||||
bool ehci_reset(int bus, int dev, int func, uintptr_t base_addr);
|
||||
|
||||
/**
|
||||
* Initialises the EHCI device at the specified base address, probes all
|
||||
* the attached USB devices, and configures any HID USB keyboard devices
|
||||
* it finds to generate periodic interrupt transfers that report key
|
||||
* presses. If successful, initialises the specified host controller
|
||||
* driver object accordingly.
|
||||
*
|
||||
* \param base_addr - the base address of the device in virtual memory
|
||||
* \param hcd - a pointer to a pre-allocated host controller
|
||||
* driver object that can be used for this device
|
||||
*
|
||||
* \returns
|
||||
* true if the device was successfully initialised and one or more
|
||||
* keyboards were found, otherwise false.
|
||||
*/
|
||||
bool ehci_probe(uintptr_t base_addr, usb_hcd_t *hcd);
|
||||
|
||||
#endif // EHCI_H
|
||||
|
|
|
@ -24,8 +24,10 @@ typedef struct {
|
|||
// Private Variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static heap_t lm_heap = { .segment = -1, .start = 0, .end = 0 };
|
||||
static heap_t hm_heap = { .segment = -1, .start = 0, .end = 0 };
|
||||
static heap_t heaps[HEAP_TYPE_LAST] = {
|
||||
{ .segment = -1, .start = 0, .end = 0 },
|
||||
{ .segment = -1, .start = 0, .end = 0 }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
|
@ -36,8 +38,9 @@ static size_t num_pages(size_t size)
|
|||
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static uintptr_t heap_alloc(const heap_t *heap, size_t size, uintptr_t alignment)
|
||||
uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment)
|
||||
{
|
||||
const heap_t * heap = &heaps[heap_id];
|
||||
if (heap->segment < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -50,16 +53,18 @@ static uintptr_t heap_alloc(const heap_t *heap, size_t size, uintptr_t alignment
|
|||
return addr << PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static uintptr_t heap_mark(const heap_t *heap)
|
||||
uintptr_t heap_mark(heap_type_t heap_id)
|
||||
{
|
||||
const heap_t * heap = &heaps[heap_id];
|
||||
if (heap->segment < 0) {
|
||||
return 0;
|
||||
}
|
||||
return pm_map[heap->segment].end;
|
||||
}
|
||||
|
||||
static void heap_rewind(const heap_t *heap, uintptr_t mark)
|
||||
void heap_rewind(heap_type_t heap_id, uintptr_t mark)
|
||||
{
|
||||
const heap_t * heap = &heaps[heap_id];
|
||||
if (heap->segment >= 0 && mark > pm_map[heap->segment].end && mark <= heap->end) {
|
||||
pm_map[heap->segment].end = mark;
|
||||
}
|
||||
|
@ -86,43 +91,13 @@ void heap_init(void)
|
|||
if (segment_size >= max_segment_size) {
|
||||
max_segment_size = segment_size;
|
||||
if (try_heap_end <= PAGE_C(1,MB)) {
|
||||
lm_heap.segment = i;
|
||||
lm_heap.start = try_heap_start;
|
||||
lm_heap.end = try_heap_end;
|
||||
heaps[HEAP_TYPE_LM_1].segment = i;
|
||||
heaps[HEAP_TYPE_LM_1].start = try_heap_start;
|
||||
heaps[HEAP_TYPE_LM_1].end = try_heap_end;
|
||||
}
|
||||
hm_heap.segment = i;
|
||||
hm_heap.start = try_heap_start;
|
||||
hm_heap.end = try_heap_end;
|
||||
heaps[HEAP_TYPE_HM_1].segment = i;
|
||||
heaps[HEAP_TYPE_HM_1].start = try_heap_start;
|
||||
heaps[HEAP_TYPE_HM_1].end = try_heap_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment)
|
||||
{
|
||||
return heap_alloc(&lm_heap, size, alignment);
|
||||
}
|
||||
|
||||
uintptr_t lm_heap_mark(void)
|
||||
{
|
||||
return heap_mark(&lm_heap);
|
||||
}
|
||||
|
||||
void lm_heap_rewind(uintptr_t mark)
|
||||
{
|
||||
heap_rewind(&lm_heap, mark);
|
||||
}
|
||||
|
||||
uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment)
|
||||
{
|
||||
return heap_alloc(&hm_heap, size, alignment);
|
||||
}
|
||||
|
||||
uintptr_t hm_heap_mark(void)
|
||||
{
|
||||
return heap_mark(&hm_heap);
|
||||
}
|
||||
|
||||
void hm_heap_rewind(uintptr_t mark)
|
||||
{
|
||||
heap_rewind(&hm_heap, mark);
|
||||
}
|
||||
|
|
|
@ -16,71 +16,50 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
HEAP_TYPE_LM_1,
|
||||
HEAP_TYPE_HM_1,
|
||||
HEAP_TYPE_LAST
|
||||
} heap_type_t;
|
||||
|
||||
/**
|
||||
* Initialises the heaps.
|
||||
*/
|
||||
void heap_init(void);
|
||||
|
||||
/**
|
||||
* Allocates a chunk of physical memory below 1MB. The allocated region will
|
||||
* be at least the requested size with the requested alignment. This memory
|
||||
* is always mapped to the identical address in virtual memory.
|
||||
* Allocates a chunk of physical memory in the given heap. The allocated
|
||||
* region will be at least the requested size with the requested alignment.
|
||||
* This memory is always mapped to the identical address in virtual memory.
|
||||
*
|
||||
* \param size - the requested size in bytes.
|
||||
* \param alignment - the requested byte alignment (must be a power of 2).
|
||||
* \param heap_id - the target heap.
|
||||
* \param size - the requested size in bytes.
|
||||
* \param alignment - the requested byte alignment (must be a power of 2).
|
||||
*
|
||||
* \returns
|
||||
* On success, the allocated address in physical memory. On failure, 0.
|
||||
*/
|
||||
uintptr_t lm_heap_alloc(size_t size, uintptr_t alignment);
|
||||
uintptr_t heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment);
|
||||
|
||||
/**
|
||||
* Returns a value indicating the current allocation state of the low-memory
|
||||
* heap. This value may be passed to lm_heap_rewind() to free any low memory
|
||||
* allocated after this call.
|
||||
* Returns a value indicating the current allocation state of the given
|
||||
* memory heap. This value may be passed to heap_rewind() to free any
|
||||
* memory from that heap allocated after this call.
|
||||
*
|
||||
* \param heap_id - the target heap.
|
||||
*
|
||||
* \returns
|
||||
* An opaque value indicating the current allocation state.
|
||||
*/
|
||||
uintptr_t lm_heap_mark(void);
|
||||
uintptr_t heap_mark(heap_type_t heap_id);
|
||||
|
||||
/**
|
||||
* Frees any low memory allocated since the specified mark was obtained from
|
||||
* a call to lm_heap_mark().
|
||||
* Frees any memory allocated in the given heap since the specified mark was
|
||||
* obtained from a call to heap_mark().
|
||||
*
|
||||
* \param mark - the mark that indicates how much memory to free.
|
||||
* \param heap_id - the target heap.
|
||||
* \param mark - the mark that indicates how much memory to free.
|
||||
*/
|
||||
void lm_heap_rewind(uintptr_t mark);
|
||||
|
||||
/**
|
||||
* Allocates a chunk of physical memory below 4GB. The allocated region will
|
||||
* be at least the requested size with the requested alignment. The caller is
|
||||
* responsible for mapping it into virtual memory if required.
|
||||
*
|
||||
* \param size - the requested size in bytes.
|
||||
* \param alignment - the requested byte alignment (must be a power of 2).
|
||||
*
|
||||
* \returns
|
||||
* On success, the allocated address in physical memory. On failure, 0.
|
||||
*/
|
||||
uintptr_t hm_heap_alloc(size_t size, uintptr_t alignment);
|
||||
|
||||
/**
|
||||
* Returns a value indicating the current allocation state of the high-memory
|
||||
* heap. This value may be passed to hm_heap_rewind() to free any high memory
|
||||
* allocated after this call.
|
||||
*
|
||||
* \returns
|
||||
* An opaque value indicating the current allocation state.
|
||||
*/
|
||||
uintptr_t hm_heap_mark(void);
|
||||
|
||||
/**
|
||||
* Frees any high memory allocated since the specified mark was obtained from
|
||||
* a call to hm_heap_mark().
|
||||
*
|
||||
* \param mark - the mark that indicates how much memory to free.
|
||||
*/
|
||||
void hm_heap_rewind(uintptr_t mark);
|
||||
void heap_rewind(heap_type_t heap_id, uintptr_t mark);
|
||||
|
||||
#endif // HEAP_H
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2004-2022 Samuel Demeulemeester
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester
|
||||
//
|
||||
// ------------------------
|
||||
// This file is used to detect quirks on specific hardware
|
||||
|
@ -13,6 +13,9 @@
|
|||
#include "pci.h"
|
||||
#include "unistd.h"
|
||||
#include "cpuinfo.h"
|
||||
#include "cpuid.h"
|
||||
#include "config.h"
|
||||
#include "temperature.h"
|
||||
|
||||
quirk_t quirk;
|
||||
|
||||
|
@ -64,6 +67,38 @@ static void get_m1541_l2_cache_size(void)
|
|||
if (reg == 0b10) { l2_cache = 1024; }
|
||||
}
|
||||
|
||||
static void disable_temp_reporting(void)
|
||||
{
|
||||
enable_temperature = false;
|
||||
}
|
||||
|
||||
static void amd_k8_revfg_temp(void)
|
||||
{
|
||||
uint32_t rtcr = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8);
|
||||
|
||||
// For Rev F & G, switch sensor if no temperature is reported
|
||||
if (!((rtcr >> 16) & 0xFF)) {
|
||||
pci_config_write8(0, 24, 3, AMD_TEMP_REG_K8, rtcr | 0x04);
|
||||
}
|
||||
|
||||
// K8 Rev G Desktop requires an additional offset.
|
||||
if (cpuid_info.version.extendedModel < 6 && cpuid_info.version.extendedModel > 7) // Not Rev G
|
||||
return;
|
||||
|
||||
if (cpuid_info.version.extendedModel == 6 && cpuid_info.version.extendedModel < 9) // Not Desktop
|
||||
return;
|
||||
|
||||
uint16_t brandID = (cpuid_info.version.extendedBrandID >> 9) & 0x1f;
|
||||
|
||||
if (cpuid_info.version.model == 0xF && (brandID == 0x7 || brandID == 0x9 || brandID == 0xC)) // Mobile (Single Core)
|
||||
return;
|
||||
|
||||
if (cpuid_info.version.model == 0xB && brandID > 0xB) // Mobile (Dual Core)
|
||||
return;
|
||||
|
||||
cpu_temp_offset = 21.0f;
|
||||
}
|
||||
|
||||
// ---------------------
|
||||
// -- Public function --
|
||||
// ---------------------
|
||||
|
@ -72,16 +107,16 @@ void quirks_init(void)
|
|||
{
|
||||
quirk.id = QUIRK_NONE;
|
||||
quirk.type = QUIRK_TYPE_NONE;
|
||||
quirk.root_vid = pci_config_read16(0, 0, 0, 0);
|
||||
quirk.root_did = pci_config_read16(0, 0, 0, 2);
|
||||
quirk.root_vid = pci_config_read16(0, 0, 0, PCI_VID_REG);
|
||||
quirk.root_did = pci_config_read16(0, 0, 0, PCI_DID_REG);
|
||||
quirk.process = NULL;
|
||||
|
||||
// -------------------------
|
||||
// -- ALi Aladdin V Quirk --
|
||||
// -------------------------
|
||||
// As on many Socket 7 Motherboard, the L2 cache is external and must
|
||||
// As on many Socket 7 Motherboards, the L2 cache is external and must
|
||||
// be detected by a proprietary way based on chipset registers
|
||||
if (quirk.root_vid == 0x10B9 && quirk.root_did == 0x1541) { // ALi Aladdin V (M1541)
|
||||
if (quirk.root_vid == PCI_VID_ALI && quirk.root_did == 0x1541) { // ALi Aladdin V (M1541)
|
||||
quirk.id = QUIRK_ALI_ALADDIN_V;
|
||||
quirk.type |= QUIRK_TYPE_MEM_SIZE;
|
||||
quirk.process = get_m1541_l2_cache_size;
|
||||
|
@ -93,13 +128,75 @@ void quirks_init(void)
|
|||
// This motherboard has an ASB100 ASIC with a SMBUS Mux Integrated.
|
||||
// To access SPD later in the code, we need to configure the mux.
|
||||
// PS: Detection via DMI is unreliable, so using Root PCI Registers
|
||||
if (quirk.root_vid == 0x8086 && quirk.root_did == 0x1130) { // Intel i815
|
||||
if (pci_config_read16(0, 0, 0, 0x2C) == 0x1043) { // ASUS
|
||||
if (pci_config_read16(0, 0, 0, 0x2E) == 0x8027) { // TUSL2-C
|
||||
if (quirk.root_vid == PCI_VID_INTEL && quirk.root_did == 0x1130) { // Intel i815
|
||||
if (pci_config_read16(0, 0, 0, PCI_SUB_VID_REG) == PCI_VID_ASUS) { // ASUS
|
||||
if (pci_config_read16(0, 0, 0, PCI_SUB_DID_REG) == 0x8027) { // TUSL2-C
|
||||
quirk.id = QUIRK_TUSL2;
|
||||
quirk.type |= QUIRK_TYPE_SMBUS;
|
||||
quirk.process = asus_tusl2_configure_mux;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// -- SuperMicro X10SDV Quirk (GitHub Issue #233) --
|
||||
// -------------------------------------------------
|
||||
// Memtest86+ crashs on Super Micro X10SDV motherboard with SMP Enabled
|
||||
// We were unable to find a solution so far, so disable SMP by default
|
||||
if (quirk.root_vid == PCI_VID_INTEL && quirk.root_did == 0x6F00) { // Broadwell-E (Xeon-D)
|
||||
if (pci_config_read16(0, 0, 0, PCI_SUB_VID_REG) == PCI_VID_SUPERMICRO) { // Super Micro
|
||||
quirk.id = QUIRK_X10SDV_NOSMP;
|
||||
quirk.type |= QUIRK_TYPE_SMP;
|
||||
quirk.process = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------
|
||||
// -- Early AMD K8 doesn't support temperature reading --
|
||||
// ------------------------------------------------------
|
||||
// The on-die temperature diode on SH-B0/B3 stepping does not work.
|
||||
if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF
|
||||
&& cpuid_info.version.extendedFamily == 0 && cpuid_info.version.extendedModel == 0) { // Early K8
|
||||
if ((cpuid_info.version.model == 4 && cpuid_info.version.stepping == 0) || // SH-B0 ClawHammer (Athlon 64)
|
||||
(cpuid_info.version.model == 5 && cpuid_info.version.stepping <= 1)) { // SH-B0/B3 SledgeHammer (Opteron)
|
||||
quirk.id = QUIRK_K8_BSTEP_NOTEMP;
|
||||
quirk.type |= QUIRK_TYPE_TEMP;
|
||||
quirk.process = disable_temp_reporting;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
// -- Late AMD K8 (rev F/G) temp sensor workaround --
|
||||
// ---------------------------------------------------
|
||||
if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF
|
||||
&& cpuid_info.version.extendedFamily == 0 && cpuid_info.version.extendedModel >= 4) { // Later K8
|
||||
|
||||
quirk.id = QUIRK_K8_REVFG_TEMP;
|
||||
quirk.type |= QUIRK_TYPE_TEMP;
|
||||
quirk.process = amd_k8_revfg_temp;
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// -- AMD K10 CPUs Temp workaround (Errata #319) --
|
||||
// ------------------------------------------------
|
||||
// Some AMD K10 CPUs on Socket AM2+/F have buggued thermal diode leading
|
||||
// to inaccurate temperature measurements. Affected steppings: DR-BA/B2/B3, RB-C2 & HY-D0.
|
||||
if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF
|
||||
&& cpuid_info.version.extendedFamily == 1 && cpuid_info.version.extendedModel == 0) { // AMD K10
|
||||
|
||||
uint8_t pkg_type = (cpuid_info.version.extendedBrandID >> 28) & 0x0F;
|
||||
uint32_t dct0_high = pci_config_read32(0, 24, 2, 0x94); // 0x94[8] = 1 for DDR3
|
||||
|
||||
if (pkg_type == 0b0000 || (pkg_type == 0b0001 && (((dct0_high >> 8) & 1) == 0))) { // Socket F or AM2+ (exclude AM3)
|
||||
|
||||
if (cpuid_info.version.model < 4 || // DR-BA, DR-B2 & DR-B3
|
||||
(cpuid_info.version.model == 4 && cpuid_info.version.stepping <= 2) || // RB-C2
|
||||
cpuid_info.version.model == 8) { // HY-D0
|
||||
|
||||
quirk.id = QUIRK_AMD_ERRATA_319;
|
||||
quirk.type |= QUIRK_TYPE_TEMP;
|
||||
quirk.process = disable_temp_reporting;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,16 @@
|
|||
#define QUIRK_TYPE_SMBUS (1 << 4)
|
||||
#define QUIRK_TYPE_TIMER (1 << 5)
|
||||
#define QUIRK_TYPE_MEM_SIZE (1 << 6)
|
||||
#define QUIRK_TYPE_TEMP (1 << 7)
|
||||
|
||||
typedef enum {
|
||||
QUIRK_NONE,
|
||||
QUIRK_TUSL2,
|
||||
QUIRK_ALI_ALADDIN_V
|
||||
QUIRK_ALI_ALADDIN_V,
|
||||
QUIRK_X10SDV_NOSMP,
|
||||
QUIRK_K8_BSTEP_NOTEMP,
|
||||
QUIRK_K8_REVFG_TEMP,
|
||||
QUIRK_AMD_ERRATA_319
|
||||
} quirk_id_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -79,7 +79,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x003D, "Tektronix" },
|
||||
// { 0x003E, "Oracle Corporation" },
|
||||
// { 0x003F, "Silicon Storage Technology" },
|
||||
// { 0x0040, "ProMos/Mosel Vitelic" },
|
||||
{ 0x0040, "MOSEL" },
|
||||
{ 0x0041, "Infineon" },
|
||||
{ 0x0042, "Macronix" },
|
||||
// { 0x0043, "Xerox" },
|
||||
|
@ -161,7 +161,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0111, "DATARAM" },
|
||||
// { 0x0112, "United Microelectronics Corp" },
|
||||
// { 0x0113, "TCSI" },
|
||||
// { 0x0114, "Smart Modular" },
|
||||
{ 0x0114, "Smart Modular" },
|
||||
// { 0x0115, "Hughes Aircraft" },
|
||||
// { 0x0116, "Lanstar Semiconductor" },
|
||||
// { 0x0117, "Qlogic" },
|
||||
|
@ -392,7 +392,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x027B, "Accelerant Networks" },
|
||||
// { 0x027C, "Silicon Wave" },
|
||||
// { 0x027D, "SandCraft" },
|
||||
// { 0x027E, "Elpida" },
|
||||
{ 0x027E, "Elpida" },
|
||||
// { 0x0301, "Solectron" },
|
||||
// { 0x0302, "Optosys Technologies" },
|
||||
// { 0x0303, "Buffalo (Formerly Melco)" },
|
||||
|
@ -407,14 +407,14 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x030C, "Elite Flash Storage" },
|
||||
// { 0x030D, "Mysticom" },
|
||||
// { 0x030E, "LightSand Communications" },
|
||||
// { 0x030F, "ATI Technologies" },
|
||||
{ 0x030F, "ATI" },
|
||||
// { 0x0310, "Agere Systems" },
|
||||
// { 0x0311, "NeoMagic" },
|
||||
// { 0x0312, "AuroraNetics" },
|
||||
// { 0x0313, "Golden Empire" },
|
||||
{ 0x0313, "GEIL" },
|
||||
{ 0x0314, "Mushkin" },
|
||||
// { 0x0315, "Tioga Technologies" },
|
||||
// { 0x0316, "Netlist" },
|
||||
{ 0x0316, "Netlist" },
|
||||
// { 0x0317, "TeraLogic" },
|
||||
// { 0x0318, "Cicada Semiconductor" },
|
||||
// { 0x0319, "Centon Electronics" },
|
||||
|
@ -478,9 +478,9 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0353, "Primarion" },
|
||||
// { 0x0354, "Picochip Designs Ltd" },
|
||||
// { 0x0355, "Silverback Systems" },
|
||||
// { 0x0356, "Jade Star Technologies" },
|
||||
{ 0x0356, "Jade Star" },
|
||||
// { 0x0357, "Pijnenburg Securealink" },
|
||||
// { 0x0358, "takeMS - Ultron AG" },
|
||||
{ 0x0358, "takeMS" }, // Ultron AG
|
||||
// { 0x0359, "Cambridge Silicon Radio" },
|
||||
{ 0x035A, "Swissbit" },
|
||||
// { 0x035B, "Nazomi Communications" },
|
||||
|
@ -540,7 +540,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0413, "Digital Communications Technology Inc" },
|
||||
// { 0x0414, "Silicon-Based Technology" },
|
||||
// { 0x0415, "Fulcrum Microsystems" },
|
||||
// { 0x0416, "Positivo Informatica Ltd" },
|
||||
{ 0x0416, "Positivo" },
|
||||
// { 0x0417, "XIOtech Corporation" },
|
||||
// { 0x0418, "PortalPlayer" },
|
||||
// { 0x0419, "Zhiying Software" },
|
||||
|
@ -585,7 +585,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0440, "Bandspeed" },
|
||||
// { 0x0441, "LeWiz Communications" },
|
||||
// { 0x0442, "CPU Technology" },
|
||||
// { 0x0443, "Ramaxel Technology" },
|
||||
{ 0x0443, "Ramaxel" },
|
||||
// { 0x0444, "DSP Group" },
|
||||
// { 0x0445, "Axis Communications" },
|
||||
// { 0x0446, "Legacy Electronics" },
|
||||
|
@ -706,7 +706,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x053B, "Solid State System Co Ltd" },
|
||||
// { 0x053C, "Kian Tech LLC" },
|
||||
// { 0x053D, "Artimi" },
|
||||
// { 0x053E, "Power Quotient International" },
|
||||
{ 0x053E, "PQI" },
|
||||
// { 0x053F, "Avago Technologies" },
|
||||
// { 0x0540, "ADTechnology" },
|
||||
// { 0x0541, "Sigma Designs" },
|
||||
|
@ -730,20 +730,20 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0553, "Velogix" },
|
||||
// { 0x0554, "Montalvo Systems" },
|
||||
// { 0x0555, "iVivity Inc" },
|
||||
// { 0x0556, "Walton Chaintech" },
|
||||
// { 0x0557, "AENEON" },
|
||||
{ 0x0556, "Walton Chaintech" },
|
||||
{ 0x0557, "AENEON" },
|
||||
// { 0x0558, "Lorom Industrial Co Ltd" },
|
||||
// { 0x0559, "Radiospire Networks" },
|
||||
// { 0x055A, "Sensio Technologies Inc" },
|
||||
// { 0x055B, "Nethra Imaging" },
|
||||
// { 0x055C, "Hexon Technology Pte Ltd" },
|
||||
{ 0x055C, "Hexon" },
|
||||
// { 0x055D, "CompuStocx (CSX)" },
|
||||
// { 0x055E, "Methode Electronics Inc" },
|
||||
// { 0x055F, "Connect One Ltd" },
|
||||
// { 0x0560, "Opulan Technologies" },
|
||||
// { 0x0561, "Septentrio NV" },
|
||||
// { 0x0562, "Goldenmars Technology Inc" },
|
||||
// { 0x0563, "Kreton Corporation" },
|
||||
{ 0x0562, "Goldenmars" },
|
||||
{ 0x0563, "Kreton Corp." },
|
||||
// { 0x0564, "Cochlear Ltd" },
|
||||
// { 0x0565, "Altair Semiconductor" },
|
||||
// { 0x0566, "NetEffect Inc" },
|
||||
|
@ -835,7 +835,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x063E, "Wilocity" },
|
||||
// { 0x063F, "Novafora Inc" },
|
||||
// { 0x0640, "iKoa Corporation" },
|
||||
// { 0x0641, "ASint Technology" },
|
||||
{ 0x0641, "ASint" },
|
||||
{ 0x0642, "Ramtron" },
|
||||
// { 0x0643, "Plato Networks Inc" },
|
||||
// { 0x0644, "IPtronics AS" },
|
||||
|
@ -874,7 +874,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0666, "Netronome" },
|
||||
// { 0x0667, "Zenverge Inc" },
|
||||
// { 0x0668, "N-trig Ltd" },
|
||||
// { 0x0669, "SanMax Technologies Inc" },
|
||||
{ 0x0669, "SanMax" },
|
||||
// { 0x066A, "Contour Semiconductor Inc" },
|
||||
{ 0x066B, "TwinMOS" },
|
||||
// { 0x066C, "Silicon Systems Inc" },
|
||||
|
@ -882,7 +882,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x066E, "Certicom Corporation" },
|
||||
// { 0x066F, "JSC ICC Milandr" },
|
||||
// { 0x0670, "PhotoFast Global Inc" },
|
||||
// { 0x0671, "InnoDisk Corporation" },
|
||||
{ 0x0671, "InnoDisk" },
|
||||
// { 0x0672, "Muscle Power" },
|
||||
// { 0x0673, "Energy Micro" },
|
||||
// { 0x0674, "Innofidei" },
|
||||
|
@ -987,7 +987,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x075A, "Bestdon Technology Co Ltd" },
|
||||
// { 0x075B, "Baysand Inc" },
|
||||
// { 0x075C, "Uroad Technology Co Ltd" },
|
||||
// { 0x075D, "Wilk Elektronik S.A." },
|
||||
{ 0x075D, "Wilk Elektronik" },
|
||||
// { 0x075E, "AAI" },
|
||||
// { 0x075F, "Harman" },
|
||||
// { 0x0760, "Berg Microelectronics Inc" },
|
||||
|
@ -1038,12 +1038,12 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0810, "Exelis" },
|
||||
// { 0x0811, "Satixfy Ltd" },
|
||||
// { 0x0812, "Galaxy Microsystems Ltd" },
|
||||
// { 0x0813, "Gloway International Co Ltd" },
|
||||
{ 0x0813, "Gloway" },
|
||||
// { 0x0814, "Lab" },
|
||||
// { 0x0815, "Smart Energy Instruments" },
|
||||
// { 0x0816, "Approved Memory Corporation" },
|
||||
// { 0x0817, "Axell Corporation" },
|
||||
// { 0x0818, "Essencore Limited" },
|
||||
{ 0x0818, "KLEVV" },
|
||||
// { 0x0819, "Phytium" },
|
||||
// { 0x081A, "Xi'an UniIC Semiconductors Co Ltd" },
|
||||
// { 0x081B, "Ambiq Micro" },
|
||||
|
@ -1098,7 +1098,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x084C, "Shenzhen Pango Microsystems Co Ltd" },
|
||||
// { 0x084D, "Vasekey" },
|
||||
// { 0x084F, "Eyenix Co Ltd" },
|
||||
// { 0x0850, "Heoriady" },
|
||||
{ 0x0850, "Heoriady" },
|
||||
// { 0x0851, "Accelerated Memory Production Inc" },
|
||||
// { 0x0852, "INVECAS Inc" },
|
||||
// { 0x0853, "AP Memory" },
|
||||
|
@ -1208,7 +1208,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x093F, "Pegasus Semiconductor (Shanghai) Co" },
|
||||
// { 0x0940, "Mythic Inc" },
|
||||
// { 0x0941, "Elmos Semiconductor AG" },
|
||||
// { 0x0942, "Kllisre" },
|
||||
{ 0x0942, "Kllisre" },
|
||||
// { 0x0943, "Shenzhen Winconway Technology" },
|
||||
// { 0x0944, "Shenzhen Xingmem Technology Corp" },
|
||||
// { 0x0945, "Gold Key Technology Co Ltd" },
|
||||
|
@ -1261,7 +1261,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0974, "Hyundai Inc" },
|
||||
// { 0x0975, "EXCELERAM" },
|
||||
// { 0x0976, "PsiKick" },
|
||||
// { 0x0977, "Netac Technology Co Ltd" },
|
||||
{ 0x0977, "Netac" },
|
||||
{ 0x0978, "PCCOOLER" },
|
||||
// { 0x0979, "Jiangsu Huacun Electronic Technology" },
|
||||
// { 0x097A, "Shenzhen Micro Innovation Industry" },
|
||||
|
@ -1335,7 +1335,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0A42, "Thermaltake Technology Co Ltd" },
|
||||
// { 0x0A43, "Shenzhen O?Yang Maile Technology Ltd" },
|
||||
// { 0x0A44, "UPMEM" },
|
||||
// { 0x0A45, "Chun Well Technology Holding Limited" },
|
||||
{ 0x0A45, "Chun Well" },
|
||||
// { 0x0A46, "Astera Labs Inc" },
|
||||
// { 0x0A47, "Winconway" },
|
||||
// { 0x0A48, "Advantech Co Ltd" },
|
||||
|
@ -1384,7 +1384,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0A73, "MCLogic Inc" },
|
||||
// { 0x0A74, "Eorex Corporation" },
|
||||
// { 0x0A75, "Arm Technology (China) Co Ltd" },
|
||||
// { 0x0A76, "Lexar Co Limited" },
|
||||
{ 0x0A76, "Lexar" },
|
||||
// { 0x0A77, "QinetiQ Group plc" },
|
||||
// { 0x0A78, "Exascend" },
|
||||
// { 0x0A79, "Hong Kong Hyunion Electronics Co Ltd" },
|
||||
|
@ -1410,7 +1410,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0B0F, "Quadratica LLC" },
|
||||
// { 0x0B10, "Anpec Electronics" },
|
||||
// { 0x0B11, "Xi'an Morebeck Semiconductor Tech Co" },
|
||||
// { 0x0B12, "Kingbank Technology Co Ltd" },
|
||||
{ 0x0B12, "Kingbank" },
|
||||
// { 0x0B13, "ITRenew Inc" },
|
||||
// { 0x0B14, "Shenzhen Eaget Innovation Tech Ltd" },
|
||||
// { 0x0B15, "Jazer" },
|
||||
|
@ -1556,7 +1556,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0C23, "Tangem AG" },
|
||||
// { 0x0C24, "FuturePath Technology (Shenzhen) Co" },
|
||||
// { 0x0C25, "RC Module" },
|
||||
// { 0x0C26, "Timetec International Inc" },
|
||||
{ 0x0C26, "Timetec" },
|
||||
// { 0x0C27, "ICMAX Technologies Co Limited" },
|
||||
// { 0x0C28, "Lynxi Technologies Ltd Co" },
|
||||
// { 0x0C29, "Guangzhou Taisupanke Computer Equipment" },
|
||||
|
@ -1611,7 +1611,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
|||
// { 0x0C5A, "Fraunhofer IPMS" },
|
||||
// { 0x0C5B, "Shenzhen Daxinlang Electronic Tech Co" },
|
||||
// { 0x0C5C, "Abacus Peripherals Private Limited" },
|
||||
// { 0x0C5D, "OLOy Technology" },
|
||||
{ 0x0C5D, "OLOy" },
|
||||
// { 0x0C5E, "Wuhan P&S Semiconductor Co Ltd" },
|
||||
// { 0x0C5F, "Sitrus Technology" },
|
||||
// { 0x0C60, "AnHui Conner Storage Co Ltd" },
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bootparams.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "usbhcd.h"
|
||||
|
||||
|
@ -212,7 +214,7 @@ static const char usb_hid_keymap[] = {
|
|||
// Public Variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
keyboard_types_t keyboard_types = KT_LEGACY | KT_USB;
|
||||
keyboard_types_t keyboard_types = KT_NONE;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
|
@ -220,6 +222,16 @@ keyboard_types_t keyboard_types = KT_LEGACY | KT_USB;
|
|||
|
||||
void keyboard_init(void)
|
||||
{
|
||||
if (keyboard_types == KT_NONE) {
|
||||
// No command line option was found, so set the default according to
|
||||
// how we were booted.
|
||||
const boot_params_t *boot_params = (boot_params_t *)boot_params_addr;
|
||||
if (boot_params->efi_info.loader_signature != 0) {
|
||||
keyboard_types = KT_USB|KT_LEGACY;
|
||||
} else {
|
||||
keyboard_types = KT_LEGACY;
|
||||
}
|
||||
}
|
||||
if (keyboard_types & KT_USB) {
|
||||
find_usb_keyboards(keyboard_types == KT_USB);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#define MSR_AMD64_NB_CFG 0xc001001f
|
||||
#define MSR_AMD64_COFVID_STATUS 0xc0010071
|
||||
|
||||
#define MSR_VIA_TEMP_C7 0x1169
|
||||
#define MSR_VIA_TEMP_NANO 0x1423
|
||||
|
||||
#define rdmsr(msr, value1, value2) \
|
||||
__asm__ __volatile__("rdmsr" \
|
||||
: "=a" (value1), \
|
||||
|
|
|
@ -243,6 +243,36 @@ typedef struct {
|
|||
// Private Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static bool reset_host_controller(ohci_op_regs_t *op_regs)
|
||||
{
|
||||
// Prepare for host controller setup (see section 5.1.1.3 of the OHCI spec.).
|
||||
switch (read32(&op_regs->control) & OHCI_CTRL_HCFS) {
|
||||
case OHCI_CTRL_HCFS_RST:
|
||||
usleep(50*MILLISEC);
|
||||
break;
|
||||
case OHCI_CTRL_HCFS_SUS:
|
||||
case OHCI_CTRL_HCFS_RES:
|
||||
flush32(&op_regs->control, OHCI_CTRL_HCFS_RES);
|
||||
usleep(20*MILLISEC);
|
||||
break;
|
||||
default: // operational
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset the host controller.
|
||||
write32(&op_regs->command_status, OHCI_CMD_HCR);
|
||||
if (!wait_until_clr(&op_regs->command_status, OHCI_CMD_HCR, 30)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check we are now in SUSPEND state.
|
||||
if ((read32(&op_regs->control) & OHCI_CTRL_HCFS) != OHCI_CTRL_HCFS_SUS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool reset_ohci_port(ohci_op_regs_t *op_regs, int port_idx)
|
||||
{
|
||||
// The OHCI reset lasts for 10ms, but the USB specification calls for 50ms (but not necessarily continuously).
|
||||
|
@ -406,11 +436,11 @@ static const hcd_methods_t methods = {
|
|||
// Public Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||
bool ohci_reset(uintptr_t base_addr)
|
||||
{
|
||||
ohci_op_regs_t *op_regs = (ohci_op_regs_t *)base_addr;
|
||||
|
||||
// Check the host controller revison.
|
||||
// Check the host controller revision.
|
||||
if ((read32(&op_regs->revision) & 0xff) != 0x10) {
|
||||
return false;
|
||||
}
|
||||
|
@ -424,6 +454,20 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
}
|
||||
}
|
||||
|
||||
// Reset the controller, but preserve the frame interval set by the SMM or BIOS.
|
||||
uint32_t fm_interval = read32(&op_regs->fm_interval);
|
||||
if (!reset_host_controller(op_regs)) {
|
||||
return false;
|
||||
}
|
||||
write32(&op_regs->fm_interval, fm_interval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ohci_probe(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||
{
|
||||
ohci_op_regs_t *op_regs = (ohci_op_regs_t *)base_addr;
|
||||
|
||||
// Preserve the frame interval set by the SMM or BIOS.
|
||||
// If not set, use the default value.
|
||||
uint32_t frame_interval = read32(&op_regs->fm_interval) & 0x3fff;
|
||||
|
@ -431,36 +475,18 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
frame_interval = 0x2edf;
|
||||
}
|
||||
|
||||
// Prepare for host controller setup (see section 5.1.1.3 of the OHCI spec.).
|
||||
switch (read32(&op_regs->control) & OHCI_CTRL_HCFS) {
|
||||
case OHCI_CTRL_HCFS_RST:
|
||||
usleep(50*MILLISEC);
|
||||
break;
|
||||
case OHCI_CTRL_HCFS_SUS:
|
||||
case OHCI_CTRL_HCFS_RES:
|
||||
flush32(&op_regs->control, OHCI_CTRL_HCFS_RES);
|
||||
usleep(10*MILLISEC);
|
||||
break;
|
||||
default: // operational
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset the host controller.
|
||||
write32(&op_regs->command_status, OHCI_CMD_HCR);
|
||||
if (!wait_until_clr(&op_regs->command_status, OHCI_CMD_HCR, 30)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check we are now in SUSPEND state.
|
||||
if ((read32(&op_regs->control) & OHCI_CTRL_HCFS) != OHCI_CTRL_HCFS_SUS) {
|
||||
// We will have already reset the controller, but can't guarantee to get
|
||||
// here within the 2ms time limit for moving directly from suspend state
|
||||
// to operational state. So reset it again.
|
||||
if (!reset_host_controller(op_regs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Record the heap state to allow us to free memory.
|
||||
uintptr_t initial_heap_mark = lm_heap_mark();
|
||||
uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||
|
||||
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
|
||||
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||
if (workspace_addr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -498,9 +524,8 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
|
||||
// Construct a hub descriptor for the root hub.
|
||||
usb_hub_t root_hub;
|
||||
memset(&root_hub, 0, sizeof(root_hub));
|
||||
root_hub.ep0 = NULL;
|
||||
root_hub.level = 0;
|
||||
root_hub.route = 0;
|
||||
root_hub.num_ports = rh_descriptor_a & 0xf;
|
||||
root_hub.power_up_delay = rh_descriptor_a >> 24;
|
||||
|
||||
|
@ -608,6 +633,6 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
return true;
|
||||
|
||||
no_keyboards_found:
|
||||
lm_heap_rewind(initial_heap_mark);
|
||||
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,12 +15,32 @@
|
|||
#include "usbhcd.h"
|
||||
|
||||
/**
|
||||
* Initialises the OHCI device found at base_addr, scans all the attached USB
|
||||
* devices, and configures any HID USB keyboard devices it finds to generate
|
||||
* periodic interrupt transfers that report key presses. Initialises hcd and
|
||||
* returns true if the device was successfully initialised and one or more
|
||||
* keyboards were found.
|
||||
* If necessary, takes ownership of the OHCI device at the specified base
|
||||
* address, then resets it.
|
||||
*
|
||||
* \param base_addr - the base address of the device in virtual memory
|
||||
*
|
||||
* \returns
|
||||
* true if ownership was acquired and the device was successfully reset,
|
||||
* otherwise false.
|
||||
*/
|
||||
bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd);
|
||||
bool ohci_reset(uintptr_t base_addr);
|
||||
|
||||
/**
|
||||
* Initialises the OHCI device at the specified base address, probes all
|
||||
* the attached USB devices, and configures any HID USB keyboard devices
|
||||
* it finds to generate periodic interrupt transfers that report key
|
||||
* presses. If successful, initialises the specified host controller
|
||||
* driver object accordingly.
|
||||
*
|
||||
* \param base_addr - the base address of the device in virtual memory
|
||||
* \param hcd - a pointer to a pre-allocated host controller
|
||||
* driver object that can be used for this device
|
||||
*
|
||||
* \returns
|
||||
* true if the device was successfully initialised and one or more
|
||||
* keyboards were found, otherwise false.
|
||||
*/
|
||||
bool ohci_probe(uintptr_t base_addr, usb_hcd_t *hcd);
|
||||
|
||||
#endif // OHCI_H
|
||||
|
|
19
system/pci.h
19
system/pci.h
|
@ -12,6 +12,25 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PCI_VID_REG 0x00
|
||||
#define PCI_DID_REG 0x02
|
||||
#define PCI_SUB_VID_REG 0x2C
|
||||
#define PCI_SUB_DID_REG 0x2E
|
||||
|
||||
/* Vendor IDs */
|
||||
#define PCI_VID_ATI 0x1002
|
||||
#define PCI_VID_AMD 0x1022
|
||||
#define PCI_VID_SIS 0x1039
|
||||
#define PCI_VID_ASUS 0x1043
|
||||
#define PCI_VID_EFAR 0x1055
|
||||
#define PCI_VID_ALI 0x10B9
|
||||
#define PCI_VID_NVIDIA 0x10DE
|
||||
#define PCI_VID_VIA 0x1106
|
||||
#define PCI_VID_SERVERWORKS 0x1166
|
||||
#define PCI_VID_SUPERMICRO 0x15D9
|
||||
#define PCI_VID_HYGON 0x1D94
|
||||
#define PCI_VID_INTEL 0x8086
|
||||
|
||||
#define PCI_MAX_BUS 256
|
||||
#define PCI_MAX_DEV 32
|
||||
#define PCI_MAX_FUNC 8
|
||||
|
|
|
@ -42,7 +42,7 @@ static const rgb_value_t vga_pallete[16] = {
|
|||
{ 255, 255, 255 } // BOLD+WHITE
|
||||
};
|
||||
|
||||
static vga_buffer_t *vga_buffer = (vga_buffer_t *)(0xb8000);
|
||||
static vga_buffer_t *vga_buffer = NULL;
|
||||
|
||||
vga_buffer_t shadow_buffer;
|
||||
|
||||
|
@ -64,7 +64,9 @@ static void vga_put_char(int row, int col, uint8_t ch, uint8_t attr)
|
|||
shadow_buffer[row][col].ch = ch;
|
||||
shadow_buffer[row][col].attr = attr;
|
||||
|
||||
(*vga_buffer)[row][col].value = shadow_buffer[row][col].value;
|
||||
if (vga_buffer) {
|
||||
(*vga_buffer)[row][col].value = shadow_buffer[row][col].value;
|
||||
}
|
||||
}
|
||||
|
||||
static void lfb8_put_char(int row, int col, uint8_t ch, uint8_t attr)
|
||||
|
@ -239,6 +241,8 @@ void screen_init(void)
|
|||
uint32_t b = ((vga_pallete[i].b * b_max) / 255) << screen_info->blue_pos;
|
||||
lfb_pallete[i] = r | g | b;
|
||||
}
|
||||
} else if (screen_info->orig_video_isVGA != VIDEO_TYPE_NONE) {
|
||||
vga_buffer = (vga_buffer_t *)(0xb8000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
945
system/smbus.c
945
system/smbus.c
File diff suppressed because it is too large
Load diff
|
@ -7,19 +7,9 @@
|
|||
*
|
||||
* Provides functions for reading SPD via SMBUS
|
||||
*
|
||||
* Copyright (C) 2004-2022 Samuel Demeulemeester.
|
||||
* Copyright (C) 2004-2023 Sam Demeulemeester.
|
||||
*/
|
||||
|
||||
/* Vendor IDs */
|
||||
#define VID_ATI 0x1002
|
||||
#define VID_AMD 0x1022
|
||||
#define VID_SIS 0x1039
|
||||
#define VID_NVIDIA 0x10DE
|
||||
#define VID_VIA 0x1106
|
||||
#define VID_SERVERWORKS 0x1166
|
||||
#define VID_HYGON 0x1D94
|
||||
#define VID_INTEL 0x8086
|
||||
|
||||
#define I2C_WRITE 0
|
||||
#define I2C_READ 1
|
||||
|
||||
|
@ -84,6 +74,44 @@
|
|||
#define NVSMBSTS_RES 0x20
|
||||
#define NVSMBSTS_STATUS 0x1f
|
||||
|
||||
/* ALi-Specific constants (M1563 & newer) */
|
||||
#define ALI_SMBHSTCNT_SIZEMASK 0x03
|
||||
#define ALI_SMBHSTSTS_BAD 0x1C
|
||||
|
||||
#define ALI_SMBHSTCNT_QUICK 0x00
|
||||
#define ALI_SMBHSTCNT_BYTE 0x01
|
||||
#define ALI_SMBHSTCNT_BYTE_DATA 0x02
|
||||
#define ALI_SMBHSTCNT_WORD_DATA 0x03
|
||||
#define ALI_SMBHSTCNT_KILL 0x04
|
||||
#define ALI_SMBHSTCNT_BLOCK 0x05
|
||||
|
||||
/* ALi-Specific constants (M1543 & older) */
|
||||
#define ALI_OLD_SMBHSTSTS_BAD 0xE0
|
||||
#define ALI_OLD_SMBHSTSTS_BUSY 0x08
|
||||
#define ALI_OLD_SMBHSTCNT_BYTE_DATA 0x20
|
||||
|
||||
#define ALI_OLD_SMBHSTCNT smbusbase + 1
|
||||
#define ALI_OLD_SMBHSTSTART smbusbase + 2
|
||||
#define ALI_OLD_SMBHSTADD smbusbase + 3
|
||||
#define ALI_OLD_SMBHSTDAT0 smbusbase + 4
|
||||
#define ALI_OLD_SMBHSTCMD smbusbase + 7
|
||||
|
||||
/** Rounding factors for timing computation
|
||||
*
|
||||
* These factors are used as a configurable CEIL() function
|
||||
* to get the upper int from a float past a specific decimal point.
|
||||
*/
|
||||
|
||||
#define DDR5_ROUNDING_FACTOR 30
|
||||
#define ROUNDING_FACTOR 0.9f
|
||||
|
||||
#define SPD_SKU_LEN 32
|
||||
|
||||
#define PIIX4_SMB_BASE_ADR_DEFAULT 0x90
|
||||
#define PIIX4_SMB_BASE_ADR_VIAPRO 0xD0
|
||||
#define PIIX4_SMB_BASE_ADR_ALI1563 0x80
|
||||
#define PIIX4_SMB_BASE_ADR_ALI1543 0x14
|
||||
|
||||
struct pci_smbus_controller {
|
||||
unsigned vendor;
|
||||
unsigned device;
|
||||
|
@ -96,14 +124,14 @@ typedef struct spd_infos {
|
|||
uint16_t jedec_code;
|
||||
uint32_t module_size;
|
||||
char *type;
|
||||
uint8_t sku[32];
|
||||
uint8_t sku_len;
|
||||
char sku[SPD_SKU_LEN + 1];
|
||||
uint8_t XMP;
|
||||
uint16_t freq;
|
||||
bool hasECC;
|
||||
uint8_t fab_year;
|
||||
uint8_t fab_week;
|
||||
uint16_t tCL;
|
||||
uint8_t tCL_dec;
|
||||
uint16_t tRCD;
|
||||
uint16_t tRP;
|
||||
uint16_t tRAS;
|
||||
|
@ -113,6 +141,7 @@ typedef struct spd_infos {
|
|||
typedef struct ram_infos {
|
||||
uint16_t freq;
|
||||
uint16_t tCL;
|
||||
uint8_t tCL_dec;
|
||||
uint16_t tRCD;
|
||||
uint16_t tRP;
|
||||
uint16_t tRAS;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "cpuid.h"
|
||||
#include "heap.h"
|
||||
#include "hwquirks.h"
|
||||
#include "memrw32.h"
|
||||
#include "memsize.h"
|
||||
#include "msr.h"
|
||||
|
@ -539,6 +540,12 @@ void smp_init(bool smp_enable)
|
|||
}
|
||||
}
|
||||
|
||||
// Process SMP Quirks
|
||||
if (quirk.type & QUIRK_TYPE_SMP) {
|
||||
// quirk.process();
|
||||
smp_enable = false;
|
||||
}
|
||||
|
||||
if (smp_enable) {
|
||||
(void)(find_cpus_in_madt() || find_cpus_in_floating_mp_struct());
|
||||
|
||||
|
@ -550,7 +557,7 @@ void smp_init(bool smp_enable)
|
|||
|
||||
// Allocate a page of low memory for AP trampoline and sync objects.
|
||||
// These need to remain pinned in place during relocation.
|
||||
smp_heap_page = lm_heap_alloc(PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT;
|
||||
smp_heap_page = heap_alloc(HEAP_TYPE_LM_1, PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT;
|
||||
|
||||
ap_startup_addr = (uintptr_t)startup;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||
// Copyright (C) 2004-2023 Sam Demeulemeester.
|
||||
//
|
||||
// Derived from an extract of memtest86+ init.c:
|
||||
//
|
||||
|
@ -16,60 +17,120 @@
|
|||
|
||||
#include "cpuid.h"
|
||||
#include "cpuinfo.h"
|
||||
#include "hwquirks.h"
|
||||
#include "msr.h"
|
||||
#include "pci.h"
|
||||
|
||||
#include "temperature.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
float cpu_temp_offset = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int get_cpu_temperature(void)
|
||||
static int TjMax = 0;
|
||||
|
||||
void get_specific_TjMax(void)
|
||||
{
|
||||
if (imc_type == 0) {
|
||||
return 0;
|
||||
// The TjMax value for some Mobile/Embedded CPUs must be read from a fixed
|
||||
// table according to their CPUID, PCI Root DID/VID or PNS.
|
||||
// Trying to read the MSR 0x1A2 on some of them trigger a reboot.
|
||||
|
||||
// Yonah C0 Step (Pentium/Core Duo T2000 & Celeron M 200/400)
|
||||
if (cpuid_info.version.raw[0] == 0x6E8) {
|
||||
TjMax = 100;
|
||||
}
|
||||
}
|
||||
|
||||
void temperature_init(void)
|
||||
{
|
||||
uint32_t regl, regh;
|
||||
|
||||
// Process temperature-related quirks
|
||||
if (quirk.type & QUIRK_TYPE_TEMP) {
|
||||
quirk.process();
|
||||
}
|
||||
|
||||
// Intel CPU
|
||||
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6) {
|
||||
if (cpuid_info.dts_pmp & 1) {
|
||||
uint32_t msrl, msrh;
|
||||
// Get TjMax for Intel CPU
|
||||
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6 && (cpuid_info.dts_pmp & 1)) {
|
||||
|
||||
rdmsr(MSR_IA32_THERM_STATUS, msrl, msrh);
|
||||
int Tabs = (msrl >> 16) & 0x7F;
|
||||
get_specific_TjMax();
|
||||
|
||||
rdmsr(MSR_IA32_TEMPERATURE_TARGET, msrl, msrh);
|
||||
int Tjunc = (msrl >> 16) & 0x7F;
|
||||
if (TjMax == 0) {
|
||||
// Generic Method using MSR 0x1A2
|
||||
rdmsr(MSR_IA32_TEMPERATURE_TARGET, regl, regh);
|
||||
TjMax = (regl >> 16) & 0x7F;
|
||||
|
||||
if (Tjunc < 50 || Tjunc > 125) {
|
||||
Tjunc = 90;
|
||||
if (TjMax < 50 || TjMax > 125) {
|
||||
TjMax = 100;
|
||||
}
|
||||
return Tjunc - Tabs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_cpu_temperature(void)
|
||||
{
|
||||
uint32_t regl, regh;
|
||||
|
||||
// Intel CPU
|
||||
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6 && (cpuid_info.dts_pmp & 1)) {
|
||||
|
||||
rdmsr(MSR_IA32_THERM_STATUS, regl, regh);
|
||||
int Tabs = (regl >> 16) & 0x7F;
|
||||
|
||||
return TjMax - Tabs;
|
||||
}
|
||||
|
||||
// AMD CPU
|
||||
if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily > 0 && cpuid_info.version.extendedFamily < 8) {
|
||||
else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.family == 0xF) { // Target only K8 & newer
|
||||
|
||||
// Untested yet
|
||||
uint32_t rtcr = pci_config_read32(0, 24, 3, 0xA4);
|
||||
int raw_temp = (rtcr >> 21) & 0x7FF;
|
||||
if (cpuid_info.version.extendedFamily >= 8) { // Target Zen µarch and newer. Use SMN to get temperature.
|
||||
|
||||
return raw_temp / 8;
|
||||
regl = amd_smn_read(SMN_THM_TCON_CUR_TMP);
|
||||
|
||||
} else if (cpuid_info.vendor_id.str[0] == 'A' && cpuid_info.version.extendedFamily >= 8) {
|
||||
if ((regl >> 19) & 0x01) {
|
||||
cpu_temp_offset = -49.0f;
|
||||
}
|
||||
|
||||
// Grab CPU Temp. for ZEN CPUs using SNM
|
||||
uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP);
|
||||
return cpu_temp_offset + 0.125f * (float)((regl >> 21) & 0x7FF);
|
||||
|
||||
float offset = 0;
|
||||
} else if (cpuid_info.version.extendedFamily > 0) { // Target K10 to K15 (Bulldozer)
|
||||
|
||||
if((tval >> 19) & 0x01) {
|
||||
offset = -49.0f;
|
||||
regl = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K10);
|
||||
int raw_temp = ((regl >> 21) & 0x7FF) / 8;
|
||||
|
||||
return (raw_temp > 0) ? raw_temp : 0;
|
||||
|
||||
} else { // Target K8 (CPUID ExtFamily = 0)
|
||||
|
||||
regl = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K8);
|
||||
int raw_temp = ((regl >> 16) & 0xFF) - 49 + cpu_temp_offset;
|
||||
|
||||
return (raw_temp > 0) ? raw_temp : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// VIA/Centaur/Zhaoxin CPU
|
||||
else if (cpuid_info.vendor_id.str[0] == 'C' && cpuid_info.vendor_id.str[1] == 'e'
|
||||
&& (cpuid_info.version.family == 6 || cpuid_info.version.family == 7)) {
|
||||
|
||||
uint32_t msr_temp;
|
||||
|
||||
if (cpuid_info.version.family == 7 || cpuid_info.version.model == 0xF) {
|
||||
msr_temp = MSR_VIA_TEMP_NANO; // Zhaoxin, Nano
|
||||
} else if (cpuid_info.version.model == 0xA || cpuid_info.version.model == 0xD) {
|
||||
msr_temp = MSR_VIA_TEMP_C7; // C7 A/D
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return offset + 0.125f * (float)((tval >> 21) & 0x7FF);
|
||||
rdmsr(msr_temp, regl, regh);
|
||||
return (int)(regl & 0xffffff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -8,8 +8,22 @@
|
|||
*
|
||||
*//*
|
||||
* Copyright (C) 2020-2022 Martin Whitaker.
|
||||
* Copyright (C) 2003-2023 Sam Demeulemeester.
|
||||
*/
|
||||
|
||||
#define AMD_TEMP_REG_K8 0xE4
|
||||
#define AMD_TEMP_REG_K10 0xA4
|
||||
|
||||
/**
|
||||
* Global CPU Temperature offset
|
||||
*/
|
||||
extern float cpu_temp_offset;
|
||||
|
||||
/**
|
||||
* Init temperature sensor and compute offsets if needed
|
||||
*/
|
||||
void temperature_init(void);
|
||||
|
||||
/**
|
||||
* Returns the current temperature of the CPU. Returns 0 if
|
||||
* the temperature cannot be read.
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#define PIT_TICKS_50mS 59659 // PIT clock is 1.193182MHz
|
||||
#define APIC_TICKS_50mS 178977 // APIC clock is 3.579545MHz
|
||||
#define BENCH_MIN_START_ADR 0x1000000 // 16MB
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
|
@ -39,6 +38,9 @@ static void correct_tsc(void)
|
|||
|
||||
counter = inl(acpi_config.pm_addr);
|
||||
|
||||
// Generate a dirty delay
|
||||
for(volatile uint8_t i=0; i<100u; i++);
|
||||
|
||||
// Make sure counter is incrementing
|
||||
if (inl(acpi_config.pm_addr) > counter) {
|
||||
|
||||
|
|
|
@ -420,7 +420,7 @@ static const hcd_methods_t methods = {
|
|||
// Public Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
|
||||
bool uhci_reset(int bus, int dev, int func, uint16_t io_base)
|
||||
{
|
||||
// Disable PCI and SMM interrupts.
|
||||
pci_config_write16(bus, dev, func, UHCI_LEGSUP, UHCI_LEGSUP_CLEAR);
|
||||
|
@ -429,18 +429,23 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
|
|||
if (!halt_host_controller(io_base)) return false;
|
||||
if (!reset_host_controller(io_base)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uhci_probe(uint16_t io_base, usb_hcd_t *hcd)
|
||||
{
|
||||
// Record the heap state to allow us to free memory.
|
||||
uintptr_t initial_heap_mark = lm_heap_mark();
|
||||
uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||
|
||||
// Allocate the frame list. This needs to be aligned on a 4K page boundary.
|
||||
uintptr_t fl_addr = lm_heap_alloc(UHCI_FL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
|
||||
uintptr_t fl_addr = heap_alloc(HEAP_TYPE_LM_1, UHCI_FL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
|
||||
if (fl_addr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
uint32_t *fl = (uint32_t *)fl_addr;
|
||||
|
||||
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
|
||||
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||
if (workspace_addr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -474,11 +479,9 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
|
|||
|
||||
// Construct a hub descriptor for the root hub.
|
||||
usb_hub_t root_hub;
|
||||
memset(&root_hub, 0, sizeof(root_hub));
|
||||
root_hub.ep0 = NULL;
|
||||
root_hub.level = 0;
|
||||
root_hub.route = 0;
|
||||
root_hub.num_ports = MAX_UHCI_PORTS;
|
||||
root_hub.power_up_delay = 0;
|
||||
|
||||
usleep(100*MILLISEC); // USB maximum device attach time
|
||||
|
||||
|
@ -574,6 +577,6 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
|
|||
return true;
|
||||
|
||||
no_keyboards_found:
|
||||
lm_heap_rewind(initial_heap_mark);
|
||||
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,13 +15,35 @@
|
|||
#include "usbhcd.h"
|
||||
|
||||
/**
|
||||
* Initialises the UHCI device found at bus, dev, func on the PCI bus and
|
||||
* io_base in the I/O address space, scans all the attached USB devices, and
|
||||
* configures any HID USB keyboard devices it finds to generate periodic
|
||||
* interrupt transfers that report key presses. Initialises hcd and returns
|
||||
* true if the device was successfully initialised and one or more keyboards
|
||||
* were found.
|
||||
* If necessary, takes ownership of the UHCI device at the specified base
|
||||
* address, then resets it.
|
||||
*
|
||||
* \param bus - the PCI bus number for accessing the device
|
||||
* \param dev - the PCI device number for accessing the device
|
||||
* \param func - the PCI function number for accessing the device
|
||||
* \param io_base - the base address of the device in I/O space
|
||||
*
|
||||
* \returns
|
||||
* true if ownership was acquired and the device was successfully reset,
|
||||
* otherwise false.
|
||||
*/
|
||||
bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd);
|
||||
bool uhci_reset(int bus, int dev, int func, uint16_t io_base);
|
||||
|
||||
/**
|
||||
* Initialises the UHCI device at the specified base address, probes all
|
||||
* the attached USB devices, and configures any HID USB keyboard devices
|
||||
* it finds to generate periodic interrupt transfers that report key
|
||||
* presses. If successful, initialises the specified host controller
|
||||
* driver object accordingly.
|
||||
*
|
||||
* \param io_base - the base address of the device in I/O space
|
||||
* \param hcd - a pointer to a pre-allocated host controller
|
||||
* driver object that can be used for this device
|
||||
*
|
||||
* \returns
|
||||
* true if the device was successfully initialised and one or more
|
||||
* keyboards were found, otherwise false.
|
||||
*/
|
||||
bool uhci_probe(uint16_t io_base, usb_hcd_t *hcd);
|
||||
|
||||
#endif // UHCI_H
|
||||
|
|
229
system/usbhcd.c
229
system/usbhcd.c
|
@ -22,7 +22,9 @@
|
|||
// Constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define MAX_USB_CONTROLLERS 8 // an arbitrary limit - must match the initialisation of usb_controllers
|
||||
#define MAX_HCI 16 // an arbitrary limit - only affects stack usage
|
||||
|
||||
#define MAX_HCD 8 // an arbitrary limit - must match the initialisation of hcd_list
|
||||
|
||||
#define PAUSE_IF_NONE_TIME 10 // seconds
|
||||
|
||||
|
@ -41,6 +43,15 @@ typedef enum {
|
|||
MAX_HCI_TYPE = 4
|
||||
} hci_type_t;
|
||||
|
||||
typedef struct {
|
||||
hci_type_t type;
|
||||
uint8_t bus;
|
||||
uint8_t dev;
|
||||
uint8_t func;
|
||||
uintptr_t pm_base_addr;
|
||||
uintptr_t vm_base_addr;
|
||||
} hci_info_t;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Private Variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -60,7 +71,7 @@ static const hcd_methods_t methods = {
|
|||
};
|
||||
|
||||
// All entries in this array must be initialised in order to generate the necessary relocation records.
|
||||
static usb_hcd_t usb_controllers[MAX_USB_CONTROLLERS] = {
|
||||
static usb_hcd_t hcd_list[MAX_HCD] = {
|
||||
{ &methods, NULL },
|
||||
{ &methods, NULL },
|
||||
{ &methods, NULL },
|
||||
|
@ -71,7 +82,7 @@ static usb_hcd_t usb_controllers[MAX_USB_CONTROLLERS] = {
|
|||
{ &methods, NULL }
|
||||
};
|
||||
|
||||
static int num_usb_controllers = 0;
|
||||
static int num_hcd = 0;
|
||||
|
||||
static int print_row = 0;
|
||||
static int print_col = 0;
|
||||
|
@ -136,6 +147,8 @@ static bool build_hub_info(const usb_hcd_t *hcd, const usb_hub_t *parent, int po
|
|||
hub->num_ports = hub_desc.num_ports;
|
||||
hub->tt_think_time = hub_desc.characteristics & 0x0060 >> 5;
|
||||
hub->power_up_delay = hub_desc.power_up_delay;
|
||||
hub->hs_parent = usb_hs_parent(parent, port_num, ep0->device_speed);
|
||||
|
||||
usb_endpoint_desc_t *ep1_desc = find_hub_endpoint_descriptor(hcd->ws->data_buffer, hcd->ws->data_length);
|
||||
if (ep1_desc == NULL) {
|
||||
return false;
|
||||
|
@ -347,8 +360,56 @@ static bool scan_hub_ports(const usb_hcd_t *hcd, const usb_hub_t *hub, int *num_
|
|||
return keyboard_found;
|
||||
}
|
||||
|
||||
static void probe_usb_controller(int bus, int dev, int func, hci_type_t controller_type)
|
||||
static int find_usb_controllers(hci_info_t hci_list[])
|
||||
{
|
||||
int num_hci = 0;
|
||||
for (int bus = 0; bus < PCI_MAX_BUS; bus++) {
|
||||
for (int dev = 0; dev < PCI_MAX_DEV; dev++) {
|
||||
for (int func = 0; func < PCI_MAX_FUNC; func++) {
|
||||
// Test for device/function present.
|
||||
uint16_t vendor_id = pci_config_read16(bus, dev, func, 0x00);
|
||||
uint8_t hdr_type = pci_config_read8 (bus, dev, func, 0x0e);
|
||||
if (vendor_id != 0xffff) {
|
||||
// Test for a USB controller.
|
||||
uint16_t class_code = pci_config_read16(bus, dev, func, 0x0a);
|
||||
if (class_code == 0x0c03) {
|
||||
hci_type_t controller_type = pci_config_read8(bus, dev, func, 0x09) >> 4;
|
||||
if (controller_type < MAX_HCI_TYPE) {
|
||||
hci_list[num_hci].type = controller_type;
|
||||
hci_list[num_hci].bus = bus;
|
||||
hci_list[num_hci].dev = dev;
|
||||
hci_list[num_hci].func = func;
|
||||
num_hci++;
|
||||
// If we've filled the table, abort now.
|
||||
if (num_hci == MAX_HCI) {
|
||||
return num_hci;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Break out if this is a single function device.
|
||||
if (func == 0 && (hdr_type & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Break out if no device is present.
|
||||
if (func == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return num_hci;
|
||||
}
|
||||
|
||||
static void reset_usb_controller(hci_info_t *hci)
|
||||
{
|
||||
hci_type_t controller_type = hci->type;
|
||||
|
||||
int bus = hci->bus;
|
||||
int dev = hci->dev;
|
||||
int func = hci->func;
|
||||
|
||||
uint16_t vendor_id = pci_config_read16(bus, dev, func, 0x00);
|
||||
uint16_t device_id = pci_config_read16(bus, dev, func, 0x02);
|
||||
uint16_t pci_status = pci_config_read16(bus, dev, func, 0x06);
|
||||
|
@ -380,26 +441,33 @@ static void probe_usb_controller(int bus, int dev, int func, hci_type_t controll
|
|||
// Restore access to the device and set the bus master flag in case the BIOS hasn't.
|
||||
pci_config_write16(bus, dev, func, 0x04, pci_command | (in_io_space ? 0x0005 : 0x0006));
|
||||
|
||||
hci->pm_base_addr = base_addr;
|
||||
|
||||
print_usb_info("Found %s controller %04x:%04x at %08x size %08x in %s space", hci_name[controller_type],
|
||||
(uintptr_t)vendor_id, (uintptr_t)device_id, base_addr, mmio_size, in_io_space ? "I/O" : "Mem");
|
||||
|
||||
if (in_io_space) {
|
||||
if (controller_type != UHCI) {
|
||||
print_usb_info(" Unsupported address mapping for this controller type");
|
||||
hci->type = NOT_HCI; // mark this controller as unusable
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (controller_type == UHCI) {
|
||||
print_usb_info(" Unsupported address mapping for this controller type");
|
||||
hci->type = NOT_HCI; // mark this controller as unusable
|
||||
return;
|
||||
}
|
||||
base_addr = map_region(base_addr, mmio_size, false);
|
||||
if (base_addr == 0) {
|
||||
print_usb_info(" Failed to map device into virtual memory");
|
||||
hci->type = NOT_HCI; // mark this controller as unusable
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hci->vm_base_addr = base_addr;
|
||||
|
||||
// Search for power management capability.
|
||||
//uint8_t pm_cap_ptr;
|
||||
if (pci_status & 0x10) {
|
||||
|
@ -420,22 +488,53 @@ static void probe_usb_controller(int bus, int dev, int func, hci_type_t controll
|
|||
}
|
||||
}
|
||||
|
||||
// Initialise the device according to its type.
|
||||
// Reset the device according to its type.
|
||||
bool success = false;
|
||||
switch (controller_type) {
|
||||
case UHCI:
|
||||
success = uhci_reset(bus, dev, func, base_addr);
|
||||
break;
|
||||
case OHCI:
|
||||
success = ohci_reset(base_addr);
|
||||
break;
|
||||
case EHCI:
|
||||
success = ehci_reset(bus, dev, func, base_addr);
|
||||
break;
|
||||
case XHCI:
|
||||
success = xhci_reset(base_addr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!success) {
|
||||
hci->type = NOT_HCI; // mark this controller as unusable
|
||||
}
|
||||
}
|
||||
|
||||
static void probe_usb_controller(hci_type_t controller_type, uintptr_t pm_base_addr, uintptr_t vm_base_addr)
|
||||
{
|
||||
print_usb_info("Probing %s controller at %08x", hci_name[controller_type], pm_base_addr);
|
||||
|
||||
// Probe the device according to its type.
|
||||
bool keyboards_found = false;
|
||||
if (controller_type == UHCI) {
|
||||
keyboards_found = uhci_init(bus, dev, func, base_addr, &usb_controllers[num_usb_controllers]);
|
||||
}
|
||||
if (controller_type == OHCI) {
|
||||
keyboards_found = ohci_init(base_addr, &usb_controllers[num_usb_controllers]);
|
||||
}
|
||||
if (controller_type == EHCI) {
|
||||
keyboards_found = ehci_init(bus, dev, func, base_addr, &usb_controllers[num_usb_controllers]);
|
||||
}
|
||||
if (controller_type == XHCI) {
|
||||
keyboards_found = xhci_init(base_addr, &usb_controllers[num_usb_controllers]);
|
||||
switch (controller_type) {
|
||||
case UHCI:
|
||||
keyboards_found = uhci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||
break;
|
||||
case OHCI:
|
||||
keyboards_found = ohci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||
break;
|
||||
case EHCI:
|
||||
keyboards_found = ehci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||
break;
|
||||
case XHCI:
|
||||
keyboards_found = xhci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (keyboards_found) {
|
||||
num_usb_controllers++;
|
||||
num_hcd++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -456,6 +555,20 @@ uint32_t usb_route(const usb_hub_t *hub, int port_num)
|
|||
return hub->route | (port_num << (4 * (hub->level - 1)));
|
||||
}
|
||||
|
||||
usb_parent_t usb_hs_parent(const usb_hub_t *hub, int port_num, usb_speed_t device_speed)
|
||||
{
|
||||
usb_parent_t hs_parent = { 0, 0 };
|
||||
if (device_speed < USB_SPEED_HIGH && hub->level > 0) {
|
||||
if (hub->ep0->device_speed < USB_SPEED_HIGH) {
|
||||
hs_parent = hub->hs_parent;
|
||||
} else {
|
||||
hs_parent.device_id = hub->ep0->device_id;
|
||||
hs_parent.port_num = port_num;
|
||||
}
|
||||
}
|
||||
return hs_parent;
|
||||
}
|
||||
|
||||
bool wait_until_clr(const volatile uint32_t *reg, uint32_t bit_mask, int max_time)
|
||||
{
|
||||
int timer = max_time >> 3;
|
||||
|
@ -719,62 +832,40 @@ void find_usb_keyboards(bool pause_if_none)
|
|||
clear_screen();
|
||||
print_usb_info("Scanning for USB keyboards...");
|
||||
|
||||
num_usb_controllers = 0;
|
||||
for (int bus = 0; bus < PCI_MAX_BUS; bus++) {
|
||||
for (int dev = 0; dev < PCI_MAX_DEV; dev++) {
|
||||
hci_type_t controller_type[PCI_MAX_FUNC];
|
||||
for (int func = 0; func < PCI_MAX_FUNC; func++) {
|
||||
controller_type[func] = NOT_HCI;
|
||||
}
|
||||
for (int func = 0; func < PCI_MAX_FUNC; func++) {
|
||||
// Test for device/function present.
|
||||
uint16_t vendor_id = pci_config_read16(bus, dev, func, 0x00);
|
||||
uint8_t hdr_type = pci_config_read8 (bus, dev, func, 0x0e);
|
||||
if (vendor_id != 0xffff) {
|
||||
// Test for a USB controller.
|
||||
uint16_t class_code = pci_config_read16(bus, dev, func, 0x0a);
|
||||
if (class_code == 0x0c03) {
|
||||
controller_type[func] = pci_config_read8(bus, dev, func, 0x09) >> 4;
|
||||
// We need to initialise EHCI controllers before initialising any of their companion
|
||||
// controllers, so do it now.
|
||||
if (controller_type[func] == EHCI) {
|
||||
if (~usb_init_options & USB_IGNORE_EHCI) {
|
||||
probe_usb_controller(bus, dev, func, controller_type[func]);
|
||||
}
|
||||
// If we've filled the controller table, abort now.
|
||||
if (num_usb_controllers == MAX_USB_CONTROLLERS) {
|
||||
return;
|
||||
}
|
||||
controller_type[func] = NOT_HCI; // prevent reprobing
|
||||
}
|
||||
}
|
||||
// Break out if this is a single function device.
|
||||
if (func == 0 && (hdr_type & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Break out if no device is present.
|
||||
if (func == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int func = 0; func < PCI_MAX_FUNC; func++) {
|
||||
if (controller_type[func] != NOT_HCI) {
|
||||
probe_usb_controller(bus, dev, func, controller_type[func]);
|
||||
// If we've filled the controller table, abort now.
|
||||
if (num_usb_controllers == MAX_USB_CONTROLLERS) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
hci_info_t hci_list[MAX_HCI];
|
||||
|
||||
int num_hci = find_usb_controllers(hci_list);
|
||||
|
||||
// Take ownership of all controllers and reset them.
|
||||
for (int i = 0; i < num_hci; i++) {
|
||||
reset_usb_controller(&hci_list[i]);
|
||||
}
|
||||
|
||||
num_hcd = 0;
|
||||
|
||||
// As we don't support hot plugging, we need to probe EHCI controllers before
|
||||
// probing any of their companion controllers, to ensure any low and full speed
|
||||
// devices are routed to the companion controllers before we probe them.
|
||||
for (int i = 0; i < num_hci && num_hcd < MAX_HCD; i++) {
|
||||
if (hci_list[i].type == EHCI) {
|
||||
if (~usb_init_options & USB_IGNORE_EHCI) {
|
||||
probe_usb_controller(EHCI, hci_list[i].pm_base_addr, hci_list[i].vm_base_addr);
|
||||
}
|
||||
hci_list[i].type = NOT_HCI; // prevent this controller from being scanned again
|
||||
}
|
||||
}
|
||||
|
||||
// Now probe the other controllers.
|
||||
for (int i = 0; i < num_hci && num_hcd < MAX_HCD; i++) {
|
||||
if (hci_list[i].type != NOT_HCI) {
|
||||
probe_usb_controller(hci_list[i].type, hci_list[i].pm_base_addr, hci_list[i].vm_base_addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (usb_init_options & USB_DEBUG) {
|
||||
print_usb_info("Press any key to continue...");
|
||||
while (get_key() == 0) {}
|
||||
} else if (pause_if_none && num_usb_controllers == 0) {
|
||||
} else if (pause_if_none && num_hcd == 0) {
|
||||
for (int i = PAUSE_IF_NONE_TIME; i > 0; i--) {
|
||||
print_usb_info("No USB keyboards found. Continuing in %i second%c ", i, i == 1 ? ' ' : 's');
|
||||
sleep(1);
|
||||
|
@ -785,10 +876,10 @@ void find_usb_keyboards(bool pause_if_none)
|
|||
|
||||
uint8_t get_usb_keycode(void)
|
||||
{
|
||||
for (int i = 0; i < num_usb_controllers; i++) {
|
||||
const usb_hcd_t *hcd = &usb_controllers[i];
|
||||
for (int i = 0; i < num_hcd; i++) {
|
||||
const usb_hcd_t *hcd = &hcd_list[i];
|
||||
|
||||
usb_controllers[i].methods->poll_keyboards(hcd);
|
||||
hcd->methods->poll_keyboards(hcd);
|
||||
|
||||
int kc_index_o = hcd->ws->kc_index_o;
|
||||
if (kc_index_o != hcd->ws->kc_index_i) {
|
||||
|
|
|
@ -62,6 +62,14 @@ typedef struct __attribute__ ((packed)) {
|
|||
uint8_t reserved;
|
||||
} usb_ep_t;
|
||||
|
||||
/**
|
||||
* A USB parent device descriptor (used internally by the various HCI drivers).
|
||||
*/
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t device_id;
|
||||
uint8_t port_num;
|
||||
} usb_parent_t;
|
||||
|
||||
/**
|
||||
* A USB hub descriptor (used internally by the various HCI drivers).
|
||||
*/
|
||||
|
@ -72,6 +80,8 @@ typedef struct __attribute__ ((packed)) {
|
|||
uint8_t num_ports;
|
||||
uint8_t tt_think_time;
|
||||
uint8_t power_up_delay;
|
||||
usb_parent_t hs_parent;
|
||||
uint16_t reserved;
|
||||
} usb_hub_t;
|
||||
|
||||
/**
|
||||
|
@ -210,6 +220,17 @@ static inline bool valid_usb_config_descriptor(const uint8_t *buffer)
|
|||
*/
|
||||
uint32_t usb_route(const usb_hub_t *hub, int port_num);
|
||||
|
||||
/**
|
||||
* Returns the high-speed parent device ID and port number (as defined by
|
||||
* the EHCI and XHCI specifications) for the device attached to the hub
|
||||
* port specified by hub and port_num. Returns zero values if the device
|
||||
* is operating at high speed (as specified by device_speed) or is directly
|
||||
* attached to a root hub port.
|
||||
*
|
||||
* Used internally by the various HCI drivers.
|
||||
*/
|
||||
usb_parent_t usb_hs_parent(const usb_hub_t *hub, int port_num, usb_speed_t device_speed);
|
||||
|
||||
/**
|
||||
* Waits for all the bits set in bit_mask to be cleared in the register pointed
|
||||
* to by reg or for max_time microseconds to elapse.
|
||||
|
|
|
@ -645,10 +645,10 @@ static int allocate_slot(const usb_hcd_t *hcd)
|
|||
xhci_trb_t event;
|
||||
|
||||
// Record the heap state to allow us to free memory.
|
||||
ws->initial_heap_mark = lm_heap_mark();
|
||||
ws->initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||
|
||||
// Allocate and initialise a private workspace for this device.
|
||||
uintptr_t device_workspace_addr = lm_heap_alloc(DEVICE_WS_SIZE, PAGE_SIZE);
|
||||
uintptr_t device_workspace_addr = heap_alloc(HEAP_TYPE_LM_1, DEVICE_WS_SIZE, PAGE_SIZE);
|
||||
if (device_workspace_addr == 0) {
|
||||
goto free_memory;
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ static int allocate_slot(const usb_hcd_t *hcd)
|
|||
return slot_id;
|
||||
|
||||
free_memory:
|
||||
lm_heap_rewind(ws->initial_heap_mark);
|
||||
heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -690,7 +690,7 @@ static bool release_slot(const usb_hcd_t *hcd, int slot_id)
|
|||
|
||||
write64(&ws->device_context_index[slot_id], 0);
|
||||
|
||||
lm_heap_rewind(ws->initial_heap_mark);
|
||||
heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -718,6 +718,8 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_
|
|||
|
||||
// Prepare the input context for the ADDRESS_DEVICE command.
|
||||
|
||||
memset((xhci_input_context_t *)ws->input_context_addr, 0, sizeof(xhci_input_context_t));
|
||||
|
||||
xhci_ctrl_context_t *ctrl_context = (xhci_ctrl_context_t *)ws->input_context_addr;
|
||||
ctrl_context->add_context_flags = XHCI_CONTEXT_A(0) | XHCI_CONTEXT_A(1);
|
||||
|
||||
|
@ -727,13 +729,13 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_
|
|||
uint32_t route = usb_route(hub, port_num);
|
||||
slot_context->params1 |= route & 0xfffff;
|
||||
slot_context->root_hub_port_num = route >> 24;
|
||||
if (device_speed < USB_SPEED_HIGH && hub->ep0->device_speed == USB_SPEED_HIGH) {
|
||||
slot_context->parent_slot_id = hub->ep0->device_id;
|
||||
slot_context->parent_port_num = port_num;
|
||||
}
|
||||
usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed);
|
||||
slot_context->parent_slot_id = hs_parent.device_id;
|
||||
slot_context->parent_port_num = hs_parent.port_num;
|
||||
} else {
|
||||
slot_context->root_hub_port_num = port_num;
|
||||
}
|
||||
|
||||
xhci_ep_context_t *ep_context = (xhci_ep_context_t *)(ws->input_context_addr + 2 * ws->context_size);
|
||||
ep_context->params2 = XHCI_EP_CONTROL << 3 | 3 << 1; // EP Type | CErr
|
||||
ep_context->max_burst_size = 0;
|
||||
|
@ -754,7 +756,7 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_
|
|||
|
||||
size_t fetch_length = sizeof(usb_device_desc_t);
|
||||
uint32_t command_flags = 0;
|
||||
if (device_speed < USB_SPEED_HIGH) {
|
||||
if (device_speed < USB_SPEED_HIGH || usb_init_options & USB_2_STEP_INIT) {
|
||||
fetch_length = 8;
|
||||
command_flags = XHCI_TRB_BSR;
|
||||
}
|
||||
|
@ -815,7 +817,7 @@ static bool configure_interrupt_endpoint(workspace_t *ws, const usb_ep_t *ep, in
|
|||
xhci_slot_context_t *slot_context = (xhci_slot_context_t *)(ws->input_context_addr + ws->context_size);
|
||||
slot_context->params1 = ep_id << 27 | hub_flag << 26 | (slot_context->params1 & 0x00ffffff);
|
||||
slot_context->num_ports = num_ports;
|
||||
slot_context->params2 = tt_think_time;
|
||||
slot_context->params2 = ep->device_speed == USB_SPEED_HIGH ? tt_think_time : 0;
|
||||
|
||||
xhci_ep_context_t *ep_context = (xhci_ep_context_t *)(ws->input_context_addr + (1 + ep_id) * ws->context_size);
|
||||
ep_context->params1 = 0;
|
||||
|
@ -908,12 +910,8 @@ static const hcd_methods_t methods = {
|
|||
// Public Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||
bool xhci_reset(uintptr_t base_addr)
|
||||
{
|
||||
uint8_t port_type[XHCI_MAX_PORTS];
|
||||
|
||||
memset(port_type, 0, sizeof(port_type));
|
||||
|
||||
xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)base_addr;
|
||||
|
||||
#ifdef QEMU_WORKAROUND
|
||||
|
@ -945,6 +943,44 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
timer--;
|
||||
}
|
||||
}
|
||||
ext_cap_offs = ext_cap->next_offset;
|
||||
}
|
||||
|
||||
xhci_op_regs_t *op_regs = (xhci_op_regs_t *)(base_addr + cap_regs->cap_length);
|
||||
|
||||
// Ensure the controller is halted and then reset it.
|
||||
if (!halt_host_controller(op_regs)) return false;
|
||||
if (!reset_host_controller(op_regs)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xhci_probe(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||
{
|
||||
uint8_t port_type[XHCI_MAX_PORTS];
|
||||
|
||||
memset(port_type, 0, sizeof(port_type));
|
||||
|
||||
xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)base_addr;
|
||||
|
||||
#ifdef QEMU_WORKAROUND
|
||||
xhci_cap_regs_t cap_regs_copy;
|
||||
memcpy32(&cap_regs_copy, cap_regs, sizeof(cap_regs_copy));
|
||||
cap_regs = &cap_regs_copy;
|
||||
#endif
|
||||
|
||||
// Walk the extra capabilities list.
|
||||
uintptr_t ext_cap_base = base_addr;
|
||||
uintptr_t ext_cap_offs = cap_regs->hcc_params1 >> 16;
|
||||
while (ext_cap_offs != 0) {
|
||||
ext_cap_base += ext_cap_offs * sizeof(uint32_t);
|
||||
xhci_ext_cap_t *ext_cap = (xhci_ext_cap_t *)ext_cap_base;
|
||||
|
||||
#ifdef QEMU_WORKAROUND
|
||||
xhci_ext_cap_t ext_cap_copy;
|
||||
memcpy32(&ext_cap_copy, ext_cap, sizeof(ext_cap_copy));
|
||||
ext_cap = &ext_cap_copy;
|
||||
#endif
|
||||
if (ext_cap->id == XHCI_EXT_CAP_SUPPORTED_PROTOCOL) {
|
||||
xhci_supported_protocol_t *protocol = (xhci_supported_protocol_t *)ext_cap_base;
|
||||
|
||||
|
@ -982,13 +1018,9 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
xhci_rt_regs_t *rt_regs = (xhci_rt_regs_t *)(base_addr + cap_regs->rts_offset);
|
||||
xhci_db_reg_t *db_regs = (xhci_db_reg_t *)(base_addr + cap_regs->db_offset);
|
||||
|
||||
// Ensure the controller is halted and then reset it.
|
||||
if (!halt_host_controller(op_regs)) return false;
|
||||
if (!reset_host_controller(op_regs)) return false;
|
||||
|
||||
// Record the heap states to allow us to free memory.
|
||||
uintptr_t initial_lm_heap_mark = lm_heap_mark();
|
||||
uintptr_t initial_hm_heap_mark = hm_heap_mark();
|
||||
uintptr_t initial_lm_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||
uintptr_t initial_hm_heap_mark = heap_mark(HEAP_TYPE_HM_1);
|
||||
|
||||
// Record the controller page size.
|
||||
uintptr_t xhci_page_size = (read32(&op_regs->page_size) & 0xffff) << 12;
|
||||
|
@ -1002,7 +1034,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
|
||||
// Allocate and clear the scratchpad memory on the heap. This must be aligned to the controller page size.
|
||||
uintptr_t scratchpad_size = num_scratchpad_buffers * xhci_page_size;
|
||||
uintptr_t scratchpad_paddr = hm_heap_alloc(scratchpad_size, xhci_page_size);
|
||||
uintptr_t scratchpad_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_size, xhci_page_size);
|
||||
if (scratchpad_paddr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -1018,7 +1050,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
uintptr_t device_context_index_size = (1 + max_slots) * sizeof(uint64_t);
|
||||
uintptr_t scratchpad_buffer_index_offs = round_up(device_context_index_size, 64);
|
||||
uintptr_t scratchpad_buffer_index_size = num_scratchpad_buffers * sizeof(uint64_t);
|
||||
uintptr_t device_context_index_paddr = hm_heap_alloc(scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64);
|
||||
uintptr_t device_context_index_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64);
|
||||
if (device_context_index_paddr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -1041,7 +1073,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
}
|
||||
|
||||
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||
uintptr_t workspace_addr = lm_heap_alloc(sizeof(workspace_t), PAGE_SIZE);
|
||||
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||
if (workspace_addr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -1061,7 +1093,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
ws->er_dequeue_state = WS_ER_SIZE; // cycle = 1, index = 0
|
||||
|
||||
// Allocate and initialise the input context data structure. This needs to be contained within a single page.
|
||||
ws->input_context_addr = lm_heap_alloc(XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE);
|
||||
ws->input_context_addr = heap_alloc(HEAP_TYPE_LM_1, XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE);
|
||||
if (ws->input_context_addr == 0) {
|
||||
goto no_keyboards_found;
|
||||
}
|
||||
|
@ -1090,11 +1122,9 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
|
||||
// Construct a hub descriptor for the root hub.
|
||||
usb_hub_t root_hub;
|
||||
memset(&root_hub, 0, sizeof(root_hub));
|
||||
root_hub.ep0 = NULL;
|
||||
root_hub.level = 0;
|
||||
root_hub.route = 0;
|
||||
root_hub.num_ports = cap_regs->hcs_params1 & 0xff;
|
||||
root_hub.power_up_delay = 0;
|
||||
|
||||
usleep(100*MILLISEC); // USB maximum device attach time.
|
||||
|
||||
|
@ -1167,7 +1197,7 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
|||
return true;
|
||||
|
||||
no_keyboards_found:
|
||||
lm_heap_rewind(initial_lm_heap_mark);
|
||||
hm_heap_rewind(initial_hm_heap_mark);
|
||||
heap_rewind(HEAP_TYPE_LM_1, initial_lm_heap_mark);
|
||||
heap_rewind(HEAP_TYPE_HM_1, initial_hm_heap_mark);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,12 +15,32 @@
|
|||
#include "usbhcd.h"
|
||||
|
||||
/**
|
||||
* Initialises the XHCI device found at base_addr, scans all the attached USB
|
||||
* devices, and configures any HID USB keyboard devices it finds to generate
|
||||
* periodic interrupt transfers that report key presses. Initialises hcd and
|
||||
* returns true if the device was successfully initialised and one or more
|
||||
* keyboards were found.
|
||||
* If necessary, takes ownership of the XHCI device at the specified base
|
||||
* address, then resets it.
|
||||
*
|
||||
* \param base_addr - the base address of the device in virtual memory
|
||||
*
|
||||
* \returns
|
||||
* true if ownership was acquired and the device was successfully reset,
|
||||
* otherwise false.
|
||||
*/
|
||||
bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd);
|
||||
bool xhci_reset(uintptr_t base_addr);
|
||||
|
||||
/**
|
||||
* Initialises the XHCI device at the specified base address, probes all
|
||||
* the attached USB devices, and configures any HID USB keyboard devices
|
||||
* it finds to generate periodic interrupt transfers that report key
|
||||
* presses. If successful, initialises the specified host controller
|
||||
* driver object accordingly.
|
||||
*
|
||||
* \param base_addr - the base address of the device in virtual memory
|
||||
* \param hcd - a pointer to a pre-allocated host controller
|
||||
* driver object that can be used for this device
|
||||
*
|
||||
* \returns
|
||||
* true if the device was successfully initialised and one or more
|
||||
* keyboards were found, otherwise false.
|
||||
*/
|
||||
bool xhci_probe(uintptr_t base_addr, usb_hcd_t *hcd);
|
||||
|
||||
#endif // XHCI_H
|
||||
|
|
|
@ -39,6 +39,7 @@ int test_block_move(int my_cpu, int iterations)
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
|
||||
if ((end - start) < 15) continue; // we need at least 16 words for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
@ -89,6 +90,7 @@ int test_block_move(int my_cpu, int iterations)
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
|
||||
if ((end - start) < 15) continue; // we need at least 16 words for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
@ -201,6 +203,7 @@ int test_block_move(int my_cpu, int iterations)
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
|
||||
if ((end - start) < 15) continue; // we need at least 16 words for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
|
|
@ -39,6 +39,7 @@ int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pa
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
||||
if ((end - start) < (n - 1)) continue; // we need at least n words for this test
|
||||
end -= n; // avoids pointer overflow when incrementing p
|
||||
|
||||
testword_t *p = start + offset; // we assume each chunk has at least 'n' words, so this won't overflow
|
||||
|
@ -71,6 +72,7 @@ int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pa
|
|||
for (int j = 0; j < vm_map_size; j++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
||||
if ((end - start) < (n - 1)) continue; // we need at least n words for this test
|
||||
|
||||
int k = 0;
|
||||
testword_t *p = start;
|
||||
|
@ -111,6 +113,7 @@ int test_modulo_n(int my_cpu, int iterations, testword_t pattern1, testword_t pa
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
||||
if ((end - start) < (n - 1)) continue; // we need at least n words for this test
|
||||
end -= n; // avoids pointer overflow when incrementing p
|
||||
|
||||
testword_t *p = start + offset; // we assume each chunk has at least 'offset' words, so this won't overflow
|
||||
|
|
|
@ -41,6 +41,7 @@ int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
@ -99,6 +100,7 @@ int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword
|
|||
for (int j = 0; j < vm_map_size; j++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
@ -134,6 +136,7 @@ int test_mov_inv_fixed(int my_cpu, int iterations, testword_t pattern1, testword
|
|||
for (int j = vm_map_size - 1; j >= 0; j--) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = end;
|
||||
testword_t *ps = end;
|
||||
|
|
|
@ -51,6 +51,7 @@ int test_mov_inv_random(int my_cpu)
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
@ -88,6 +89,7 @@ int test_mov_inv_random(int my_cpu)
|
|||
for (int j = 0; j < vm_map_size; j++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
|
|
@ -41,6 +41,7 @@ int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse)
|
|||
for (int i = 0; i < vm_map_size; i++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
@ -78,6 +79,7 @@ int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse)
|
|||
for (int j = 0; j < vm_map_size; j++) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = start;
|
||||
testword_t *pe = start;
|
||||
|
@ -115,6 +117,7 @@ int test_mov_inv_walk1(int my_cpu, int iterations, int offset, bool inverse)
|
|||
for (int j = vm_map_size - 1; j >= 0; j--) {
|
||||
testword_t *start, *end;
|
||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
||||
if (end < start) continue; // we need at least one word for this test
|
||||
|
||||
testword_t *p = end;
|
||||
testword_t *ps = end;
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "vmem.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "error.h"
|
||||
#include "test.h"
|
||||
|
@ -127,12 +129,20 @@ int test_own_addr1(int my_cpu)
|
|||
|
||||
int test_own_addr2(int my_cpu, int stage)
|
||||
{
|
||||
static testword_t offset = 0;
|
||||
static int last_stage = -1;
|
||||
|
||||
int ticks = 0;
|
||||
|
||||
offset = (stage == last_stage) ? offset + 1 : 1;
|
||||
testword_t offset;
|
||||
|
||||
// Calculate the offset (in pages) between the virtual address and the physical address.
|
||||
offset = (vm_map[0].pm_base_addr / VM_WINDOW_SIZE) * VM_WINDOW_SIZE;
|
||||
offset = (offset >= VM_PINNED_SIZE) ? offset - VM_PINNED_SIZE : 0;
|
||||
#ifdef __x86_64__
|
||||
// Convert to a byte address offset. This will translate the virtual address into a physical address.
|
||||
offset *= PAGE_SIZE;
|
||||
#else
|
||||
// Convert to a VM window offset. This will get added into the LSBs of the virtual address.
|
||||
offset /= VM_WINDOW_SIZE;
|
||||
#endif
|
||||
|
||||
switch (stage) {
|
||||
case 0:
|
||||
|
@ -145,6 +155,5 @@ int test_own_addr2(int my_cpu, int stage)
|
|||
break;
|
||||
}
|
||||
|
||||
last_stage = stage;
|
||||
return ticks;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
test_pattern_t test_list[NUM_TEST_PATTERNS] = {
|
||||
// ena, cpu, stgs, itrs, errs, description
|
||||
{ true, SEQ, 1, 6, 0, "[Address test, walking ones, no cache] "},
|
||||
{ true, SEQ, 1, 6, 0, "[Address test, own address in window] "},
|
||||
{false, SEQ, 1, 6, 0, "[Address test, own address in window] "},
|
||||
{ true, SEQ, 2, 6, 0, "[Address test, own address + window] "},
|
||||
{ true, PAR, 1, 6, 0, "[Moving inversions, 1s & 0s] "},
|
||||
{ true, PAR, 1, 3, 0, "[Moving inversions, 8 bit pattern] "},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue