mirror of
https://codeberg.org/libreboot/memtest86plus.git
synced 2025-07-03 15:57:06 +00:00
Compare commits
113 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 | ||
|
37cb966f39 | ||
|
187bc8609e | ||
|
034372f4bf | ||
|
e6e0f0c8e7 | ||
|
89e2643de4 | ||
|
c2e94527e1 | ||
|
6b998e82e7 | ||
|
1c88824a7d | ||
|
680e6ad79b | ||
|
231b389b3c | ||
|
a5576974cf | ||
|
eac4d03462 | ||
|
cee2d32766 | ||
|
221a66da1a | ||
|
63a07258fd | ||
|
7758adfb9d | ||
|
106eabef98 | ||
|
e86b04a14a | ||
|
6cd356f831 | ||
|
9ed7e22091 | ||
|
c9f36fd4f5 | ||
|
fa563a8cb2 |
75 changed files with 3782 additions and 1695 deletions
9
.github/dependabot.yml
vendored
Normal file
9
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Set update schedule for GitHub Actions
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
# Check for updates to GitHub Actions every weekday
|
||||||
|
interval: "daily"
|
63
.github/workflows/Linux.yml
vendored
Normal file
63
.github/workflows/Linux.yml
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
name: Build and tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "*"
|
||||||
|
paths-ignore:
|
||||||
|
- "**/README.md"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- "*"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.os }} ${{ matrix.compiler }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
compiler: [gcc, clang]
|
||||||
|
os: [ubuntu-20.04, ubuntu-22.04]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Linux Dependencies
|
||||||
|
run: sudo apt-get install build-essential gcc-multilib clang libc6-dev-i386-cross dosfstools mtools xorriso -y
|
||||||
|
|
||||||
|
- name: Make all build32
|
||||||
|
env:
|
||||||
|
C: ${{matrix.compiler}}
|
||||||
|
working-directory: ./build32
|
||||||
|
run: make -j 2 all
|
||||||
|
|
||||||
|
- name: Make clean build32
|
||||||
|
working-directory: ./build32
|
||||||
|
run: make clean
|
||||||
|
|
||||||
|
- name: Make all build64
|
||||||
|
env:
|
||||||
|
C: ${{matrix.compiler}}
|
||||||
|
working-directory: ./build64
|
||||||
|
run: make -j 2 all
|
||||||
|
|
||||||
|
- name: Make clean build64
|
||||||
|
working-directory: ./build64
|
||||||
|
run: make clean
|
||||||
|
|
||||||
|
- name: Make iso build32
|
||||||
|
env:
|
||||||
|
C: ${{matrix.compiler}}
|
||||||
|
working-directory: ./build32
|
||||||
|
run: make -j 2 iso
|
||||||
|
|
||||||
|
- name: Make iso build64
|
||||||
|
env:
|
||||||
|
C: ${{matrix.compiler}}
|
||||||
|
working-directory: ./build64
|
||||||
|
run: make -j 2 iso
|
22
.github/workflows/expired.yml
vendored
Normal file
22
.github/workflows/expired.yml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
name: 'Close stale issues and PRs'
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 */2 * *'
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v8
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
exempt-issue-milestones: 'future,alpha,beta,release'
|
||||||
|
exempt-pr-milestones: 'bugfix,improvement'
|
||||||
|
exempt-all-pr-assignees: true
|
||||||
|
stale-issue-message: 'This issue is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 30 days.'
|
||||||
|
stale-pr-message: 'This PR is stale because it has been open 120 days with no activity. Remove stale label or comment or this will be closed in 30 days.'
|
||||||
|
close-issue-message: 'This issue was closed because it has been stalled for 30 days with no activity.'
|
||||||
|
close-pr-message: 'This PR was closed because it has been stalled for 30 days with no activity.'
|
||||||
|
days-before-issue-stale: 120
|
||||||
|
days-before-pr-stale: 120
|
||||||
|
days-before-issue-close: 30
|
||||||
|
days-before-pr-close: 30
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -8,7 +8,7 @@
|
||||||
*.o
|
*.o
|
||||||
|
|
||||||
# Generated file
|
# Generated file
|
||||||
githash.h
|
build_version.h
|
||||||
|
|
||||||
# Binaries
|
# Binaries
|
||||||
memtest_shared
|
memtest_shared
|
||||||
|
|
87
README.md
87
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+
|
||||||
|
|
||||||
Memtest86+ is a stand-alone memory tester for x86 and x86-64 architecture
|
Memtest86+ is a free, open-source, stand-alone memory tester for x86 and
|
||||||
computers. It provides a more thorough memory check than that provided by
|
x86-64 architecture computers. It provides a much more thorough memory
|
||||||
BIOS memory tests.
|
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)
|
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,
|
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
|
64-bit, or EFI handover boot protocol. It should work on any Pentium class or
|
||||||
later 32-bit or 64-bit CPU.
|
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
|
## Table of Contents
|
||||||
|
|
||||||
* [Origins](#origins)
|
* [Origins](#origins)
|
||||||
|
@ -28,23 +30,24 @@ later 32-bit or 64-bit CPU.
|
||||||
* [Memtest86+ Test Algorithms](#memory-testing-philosophy)
|
* [Memtest86+ Test Algorithms](#memory-testing-philosophy)
|
||||||
* [Individual Test Descriptions](#individual-test-descriptions)
|
* [Individual Test Descriptions](#individual-test-descriptions)
|
||||||
* [Known Limitations and Bugs](#known-limitations-and-bugs)
|
* [Known Limitations and Bugs](#known-limitations-and-bugs)
|
||||||
|
* [Code Contributions](#code-contributions)
|
||||||
* [Acknowledgments](#acknowledgments)
|
* [Acknowledgments](#acknowledgments)
|
||||||
|
|
||||||
## Origins
|
## Origins
|
||||||
|
|
||||||
Memtest86+ v6.0 was based on PCMemTest, which was a fork and rewrite of the
|
Memtest86+ v6.00 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
|
earlier Memtest86+ v5, which in turn was a fork of MemTest-86. The purpose
|
||||||
of the PCMemTest rewrite was to:
|
of the PCMemTest rewrite was to:
|
||||||
|
|
||||||
* make the code more readable and easier to maintain
|
* make the code more readable and easier to maintain
|
||||||
* make the code 64-bit clean and support UEFI boot
|
* make the code 64-bit clean and support UEFI boot
|
||||||
* fix failures seen when building with newer versions of GCC
|
* 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
|
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
|
particular, no attempt was made to measure the cache and main memory speed, or
|
||||||
to identify and report the DRAM type. These features will be added back
|
to identify and report the DRAM type. These features were added back and expanded
|
||||||
in Memtest86+ v6.0 in an attempt to create an unified, fully-featured release.
|
in Memtest86+ v6.0 to create a unified, fully-featured release.
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
|
@ -69,7 +72,7 @@ booted directly by a legacy BIOS (in floppy mode) or by an intermediate
|
||||||
bootloader using the Linux 16-bit boot protocol and a `memtest.efi` binary
|
bootloader using the Linux 16-bit boot protocol and a `memtest.efi` binary
|
||||||
image file which can be booted directly by a 32-bit UEFI BIOS. Either image
|
image file which can be booted directly by a 32-bit UEFI BIOS. Either image
|
||||||
can be booted by an intermediate bootloader using the Linux 32-bit or 32-bit
|
can be booted by an intermediate bootloader using the Linux 32-bit or 32-bit
|
||||||
EFI handover boot protocols.
|
EFI handover boot protocols.
|
||||||
|
|
||||||
To build a 64-bit image, change directory into the `build64` directory and
|
To build a 64-bit image, change directory into the `build64` directory and
|
||||||
type `make`. The result is a `memtest.bin` binary image file which can be
|
type `make`. The result is a `memtest.bin` binary image file which can be
|
||||||
|
@ -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
|
GRUB as an intermediate bootloader. See the `Makefile` in the `build32` or
|
||||||
`build64` directory for details. The ISO image is both legacy and UEFI
|
`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
|
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
|
on your build system (e.g. on Debian, the required GRUB modules are located
|
||||||
the make file to match the naming on your system.
|
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
|
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+
|
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
|
* disables ACPI table parsing and the use of multiple CPU cores
|
||||||
* nobench
|
* nobench
|
||||||
* disables the integrated memory benchmark
|
* disables the integrated memory benchmark
|
||||||
|
* nobigstatus
|
||||||
|
* disables the big PASS/FAIL pop-up status display
|
||||||
* nosm
|
* nosm
|
||||||
* disables SMBUS/SPD parsing, DMI decoding and memory benchmark
|
* disables SMBUS/SPD parsing, DMI decoding and memory benchmark
|
||||||
* nopause
|
* nopause
|
||||||
|
@ -132,18 +139,25 @@ recognised:
|
||||||
* where *type* is one of
|
* where *type* is one of
|
||||||
* legacy
|
* legacy
|
||||||
* usb
|
* usb
|
||||||
* buggy-usb
|
* both
|
||||||
|
* usbdebug
|
||||||
|
* pauses after probing for USB keyboards
|
||||||
|
* usbinit=*mode*
|
||||||
|
* where *mode* is one of
|
||||||
|
* 1 = use the two-step init sequence for high speed devices
|
||||||
|
* 2 = add a second USB reset in the init sequence
|
||||||
|
* 3 = the combination of modes 1 and 2
|
||||||
* console=ttyS*x*,*y*
|
* console=ttyS*x*,*y*
|
||||||
* activate serial/tty console output, where *x* is one of the following IO port
|
* activate serial/tty console output, where *x* is one of the following IO port
|
||||||
* 0 = 0x3F8
|
* 0 = 0x3F8
|
||||||
* 1 = 0x2F8
|
* 1 = 0x2F8
|
||||||
* 2 = 0x3E8
|
* 2 = 0x3E8
|
||||||
* 3 = 0x2E8
|
* 3 = 0x2E8
|
||||||
* and *y* is an optional baud rate to choose from the following list
|
* and *y* is an optional baud rate to choose from the following list
|
||||||
* 9600
|
* 9600
|
||||||
* 19200
|
* 19200
|
||||||
* 38400
|
* 38400
|
||||||
* 54600
|
* 57600
|
||||||
* 115200 (default if not specified or invalid)
|
* 115200 (default if not specified or invalid)
|
||||||
* 230400
|
* 230400
|
||||||
|
|
||||||
|
@ -151,10 +165,9 @@ recognised:
|
||||||
|
|
||||||
Memtest86+ supports both the legacy keyboard interface (using I/O ports 0x60
|
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
|
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
|
other or both can be selected via the boot command line, If not specified on
|
||||||
default is to use both. An additional option on the boot command line is
|
the command line, the default is to use both if the system was booted in UEFI
|
||||||
`buggy-usb` which enables the longer initialisation sequence required by some
|
mode, otherwise to only use the legacy interface.
|
||||||
older USB devices.
|
|
||||||
|
|
||||||
Older BIOSs usually support USB legacy keyboard emulation, which makes USB
|
Older BIOSs usually support USB legacy keyboard emulation, which makes USB
|
||||||
keyboards act like legacy keyboards connected to ports 0x60 and 0x64. This
|
keyboards act like legacy keyboards connected to ports 0x60 and 0x64. This
|
||||||
|
@ -164,14 +177,20 @@ keyboards directly. The downside of that is that the USB controllers and
|
||||||
device drivers require some memory to be reserved for their private use,
|
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
|
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
|
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
|
**NOTE**: Some UEFI BIOSs only support USB legacy keyboard emulation when
|
||||||
you enable the Compatibility System Module (CSM) in the BIOS setup. Others
|
you enable the Compatibility System Module (CSM) in the BIOS setup. Others
|
||||||
only support it when actually booting in legacy mode.
|
only support it when actually booting in legacy mode.
|
||||||
|
|
||||||
**NOTE**: Memtest86+'s USB device drivers are work in progress. Not all USB
|
Many USB devices don't fully conform to the USB specification. If the USB
|
||||||
devices are supported yet, and there may be problems on some hardware.
|
keyboard probe hangs or fails to detect your keyboard, try the various
|
||||||
|
workarounds provided by the "usbinit" boot option.
|
||||||
|
|
||||||
|
**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
|
## Operation
|
||||||
|
|
||||||
|
@ -464,8 +483,9 @@ selected by the user.
|
||||||
|
|
||||||
### Test 2 : Address test, own address + window
|
### Test 2 : Address test, own address + window
|
||||||
|
|
||||||
Across all memory regions, each address is written with its own address plus
|
Across all memory regions, each address is written with its own virtual
|
||||||
the window number and then each address is checked for consistency. This
|
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
|
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
|
testing each window in turn. This test is performed sequentially with each
|
||||||
available CPU, regardless of the CPU sequencing mode selected by the user.
|
available CPU, regardless of the CPU sequencing mode selected by the user.
|
||||||
|
@ -529,10 +549,17 @@ of all zeros and all ones.
|
||||||
|
|
||||||
## Known Limitations and Bugs
|
## 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!
|
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
|
## Acknowledgments
|
||||||
|
|
||||||
Memtest86+ v6.0 was based on PCMemTest, developed by Martin Whitaker, which
|
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 MAX_PATTERNS 10
|
||||||
|
#define PATTERNS_SIZE (MAX_PATTERNS + 1)
|
||||||
|
|
||||||
// DEFAULT_MASK covers a uintptr_t, since that is the testing granularity.
|
// DEFAULT_MASK covers a uintptr_t, since that is the testing granularity.
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
@ -55,14 +56,16 @@ typedef struct {
|
||||||
// Private Variables
|
// Private Variables
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static pattern_t pattern[MAX_PATTERNS];
|
static pattern_t patterns[PATTERNS_SIZE];
|
||||||
static int num_patterns = 0;
|
static int num_patterns = 0;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Private Functions
|
// 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.
|
* 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);
|
*mask = COMBINE_MASK(addr1, mask1, addr2, mask2);
|
||||||
|
|
||||||
*addr = addr1 | addr2;
|
*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.
|
* Determine if pattern is already covered by an existing pattern.
|
||||||
* Return -1 if nothing below the given minimum cost can be found.
|
* 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;
|
for (int i = 0; i < num_patterns; i++) {
|
||||||
int idx = -1;
|
if (combi_cost(patterns[i].addr, patterns[i].mask, pattern.addr, pattern.mask) == 0) {
|
||||||
while (i-- > 0) {
|
return true;
|
||||||
uintptr_t tmp_cost = combi_cost(pattern[i].addr, pattern[i].mask, addr1, mask1);
|
}
|
||||||
if (tmp_cost < min_cost) {
|
}
|
||||||
|
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;
|
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.
|
* Remove entries at idx and idx+1.
|
||||||
* Return -1 if no such index exists.
|
|
||||||
*/
|
*/
|
||||||
static int relocate_index(int idx)
|
static void remove_pair(int idx)
|
||||||
{
|
{
|
||||||
uintptr_t addr = pattern[idx].addr;
|
for (int i = idx; i < num_patterns - 2; i++) {
|
||||||
uintptr_t mask = pattern[idx].mask;
|
patterns[i] = patterns[i + 2];
|
||||||
pattern[idx].addr = ~pattern[idx].addr; // Never select idx
|
}
|
||||||
int new = cheap_index(addr, mask, 1 + addresses(mask));
|
patterns[num_patterns - 1].addr = 0u;
|
||||||
pattern[idx].addr = addr;
|
patterns[num_patterns - 1].mask = 0u;
|
||||||
return new;
|
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.
|
* Get the combined entry of idx1 and idx2.
|
||||||
* This is useful to combine to `neighbouring' sections to integrate.
|
|
||||||
* Inspired on the Buddy memalloc principle in the Linux kernel.
|
|
||||||
*/
|
*/
|
||||||
static void relocate_if_free(int idx)
|
static pattern_t combined_pattern(int idx1, int idx2)
|
||||||
{
|
{
|
||||||
int newidx = relocate_index(idx);
|
pattern_t combined;
|
||||||
if (newidx >= 0) {
|
combine(
|
||||||
uintptr_t caddr, cmask;
|
patterns[idx1].addr,
|
||||||
combine(pattern[newidx].addr, pattern[newidx].mask,
|
patterns[idx1].mask,
|
||||||
pattern[ idx].addr, pattern[ idx].mask,
|
patterns[idx2].addr,
|
||||||
&caddr, &cmask);
|
patterns[idx2].mask,
|
||||||
pattern[newidx].addr = caddr;
|
&combined.addr,
|
||||||
pattern[newidx].mask = cmask;
|
&combined.mask
|
||||||
if (idx < --num_patterns) {
|
);
|
||||||
pattern[idx].addr = pattern[num_patterns].addr;
|
return combined;
|
||||||
pattern[idx].mask = pattern[num_patterns].mask;
|
}
|
||||||
}
|
|
||||||
relocate_if_free (newidx);
|
/*
|
||||||
|
* 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)
|
void badram_init(void)
|
||||||
{
|
{
|
||||||
num_patterns = 0;
|
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)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_patterns < MAX_PATTERNS) {
|
// Add entry in order sorted by .addr asc
|
||||||
pattern[num_patterns].addr = addr;
|
insert_sorted(pattern);
|
||||||
pattern[num_patterns].mask = DEFAULT_MASK;
|
|
||||||
num_patterns++;
|
// If we have more patterns than the max we need to force a merge
|
||||||
relocate_if_free(num_patterns - 1);
|
if (num_patterns > MAX_PATTERNS) {
|
||||||
} else {
|
// Find the pair that is the cheapest to merge
|
||||||
int idx = cheap_index(addr, DEFAULT_MASK, UINTPTR_MAX);
|
// merge_idx will be -1 if num_patterns < 2, but that means MAX_PATTERNS = 0 which is not a valid state anyway
|
||||||
uintptr_t caddr, cmask;
|
int merge_idx = cheapest_pair();
|
||||||
combine(pattern[idx].addr, pattern[idx].mask, addr, DEFAULT_MASK, &caddr, &cmask);
|
|
||||||
pattern[idx].addr = caddr;
|
pattern_t combined = combined_pattern(merge_idx, merge_idx + 1);
|
||||||
pattern[idx].mask = cmask;
|
|
||||||
relocate_if_free(idx);
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -214,8 +283,8 @@ void badram_display(void)
|
||||||
col = 7;
|
col = 7;
|
||||||
}
|
}
|
||||||
display_scrolled_message(col, "0x%0*x,0x%0*x",
|
display_scrolled_message(col, "0x%0*x,0x%0*x",
|
||||||
TESTWORD_DIGITS, pattern[i].addr,
|
TESTWORD_DIGITS, patterns[i].addr,
|
||||||
TESTWORD_DIGITS, pattern[i].mask);
|
TESTWORD_DIGITS, patterns[i].mask);
|
||||||
col += text_width;
|
col += text_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
85
app/config.c
85
app/config.c
|
@ -1,11 +1,9 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (C) 2020-2022 Martin Whitaker.
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
//
|
//
|
||||||
// Derived from memtest86+ config.c:
|
// Derived from memtest86+ config.c:
|
||||||
//
|
//
|
||||||
// MemTest86+ V5.00 Specific code (GPL V2.0)
|
|
||||||
// By Samuel DEMEULEMEESTER, sdemeule@memtest.org
|
|
||||||
// http://www.x86-secret.com - http://www.memtest.org
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
// config.c - MemTest-86 Version 3.4
|
// config.c - MemTest-86 Version 3.4
|
||||||
//
|
//
|
||||||
|
@ -19,6 +17,7 @@
|
||||||
#include "bootparams.h"
|
#include "bootparams.h"
|
||||||
|
|
||||||
#include "cpuinfo.h"
|
#include "cpuinfo.h"
|
||||||
|
#include "cpuid.h"
|
||||||
#include "hwctrl.h"
|
#include "hwctrl.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "memsize.h"
|
#include "memsize.h"
|
||||||
|
@ -87,8 +86,12 @@ error_mode_t error_mode = ERROR_MODE_NONE;
|
||||||
|
|
||||||
cpu_state_t cpu_state[MAX_CPUS];
|
cpu_state_t cpu_state[MAX_CPUS];
|
||||||
|
|
||||||
|
core_type_t hybrid_core_type[MAX_CPUS];
|
||||||
|
bool exclude_ecores = true;
|
||||||
|
|
||||||
bool smp_enabled = true;
|
bool smp_enabled = true;
|
||||||
|
|
||||||
|
bool enable_big_status = true;
|
||||||
bool enable_temperature = true;
|
bool enable_temperature = true;
|
||||||
bool enable_trace = false;
|
bool enable_trace = false;
|
||||||
|
|
||||||
|
@ -102,7 +105,9 @@ power_save_t power_save = POWER_SAVE_HIGH;
|
||||||
bool enable_tty = false;
|
bool enable_tty = false;
|
||||||
int tty_params_port = SERIAL_PORT_0x3F8;
|
int tty_params_port = SERIAL_PORT_0x3F8;
|
||||||
int tty_params_baud = SERIAL_DEFAULT_BAUDRATE;
|
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
|
// Private Functions
|
||||||
|
@ -170,15 +175,46 @@ static void parse_option(const char *option, const char *params)
|
||||||
{
|
{
|
||||||
if (option[0] == '\0') return;
|
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) {
|
if (strncmp(params, "legacy", 7) == 0) {
|
||||||
keyboard_types = KT_LEGACY;
|
keyboard_types = KT_LEGACY;
|
||||||
} else if (strncmp(params, "usb", 4) == 0) {
|
} else if (strncmp(params, "usb", 4) == 0) {
|
||||||
keyboard_types = KT_USB;
|
keyboard_types = KT_USB;
|
||||||
} else if (strncmp(params, "buggy-usb", 10) == 0) {
|
} else if (strncmp(params, "both", 5) == 0) {
|
||||||
keyboard_types = KT_USB;
|
keyboard_types = KT_USB|KT_LEGACY;
|
||||||
usb_init_options |= USB_EXTRA_RESET;
|
|
||||||
}
|
}
|
||||||
|
} 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) {
|
} else if (strncmp(option, "powersave", 10) == 0) {
|
||||||
if (strncmp(params, "off", 4) == 0) {
|
if (strncmp(params, "off", 4) == 0) {
|
||||||
power_save = POWER_SAVE_OFF;
|
power_save = POWER_SAVE_OFF;
|
||||||
|
@ -187,22 +223,18 @@ static void parse_option(const char *option, const char *params)
|
||||||
} else if (strncmp(params, "high", 5) == 0) {
|
} else if (strncmp(params, "high", 5) == 0) {
|
||||||
power_save = POWER_SAVE_HIGH;
|
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) {
|
} else if (strncmp(option, "trace", 6) == 0) {
|
||||||
enable_trace = true;
|
enable_trace = true;
|
||||||
} else if (strncmp(option, "usbdebug", 9) == 0) {
|
} else if (strncmp(option, "usbdebug", 9) == 0) {
|
||||||
usb_init_options |= USB_DEBUG;
|
usb_init_options |= USB_DEBUG;
|
||||||
} else if (strncmp(option, "nosm", 5) == 0) {
|
} else if (strncmp(option, "usbinit", 8) == 0) {
|
||||||
enable_sm = false;
|
if (strncmp(params, "1", 2) == 0) {
|
||||||
|
usb_init_options |= USB_2_STEP_INIT;
|
||||||
|
} else if (strncmp(params, "2", 2) == 0) {
|
||||||
|
usb_init_options |= USB_EXTRA_RESET;
|
||||||
|
} else if (strncmp(params, "3", 2) == 0) {
|
||||||
|
usb_init_options |= USB_2_STEP_INIT|USB_EXTRA_RESET;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,7 +731,14 @@ static void cpu_selection_menu(void)
|
||||||
prints(POP_R+5, POP_LI, "<F3> Add one CPU");
|
prints(POP_R+5, POP_LI, "<F3> Add one CPU");
|
||||||
prints(POP_R+6, POP_LI, "<F4> Add CPU range");
|
prints(POP_R+6, POP_LI, "<F4> Add CPU range");
|
||||||
prints(POP_R+7, POP_LI, "<F5> Add all CPUs");
|
prints(POP_R+7, POP_LI, "<F5> Add all CPUs");
|
||||||
prints(POP_R+8, POP_LI, "<F10> Exit menu");
|
if (cpuid_info.topology.is_hybrid) {
|
||||||
|
if (exclude_ecores) {
|
||||||
|
prints(POP_R+8, POP_LI, "<F6> Include E-Cores");
|
||||||
|
} else {
|
||||||
|
prints(POP_R+8, POP_LI, "<F6> Exclude E-Cores");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prints(POP_R+9, POP_LI, "<F10> Exit menu");
|
||||||
|
|
||||||
display_cpu_selection(display_offset);
|
display_cpu_selection(display_offset);
|
||||||
|
|
||||||
|
@ -722,6 +761,10 @@ static void cpu_selection_menu(void)
|
||||||
case '5':
|
case '5':
|
||||||
changed = set_all_cpus(true, display_offset);
|
changed = set_all_cpus(true, display_offset);
|
||||||
break;
|
break;
|
||||||
|
case '6':
|
||||||
|
exclude_ecores = !exclude_ecores;
|
||||||
|
prints(POP_R+8, POP_LI+6, exclude_ecores ? "Exclude" : "Include");
|
||||||
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
if (display_offset >= SEL_W) {
|
if (display_offset >= SEL_W) {
|
||||||
display_offset -= SEL_W;
|
display_offset -= SEL_W;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
|
#include "cpuid.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PAR,
|
PAR,
|
||||||
|
@ -45,8 +46,12 @@ extern error_mode_t error_mode;
|
||||||
|
|
||||||
extern cpu_state_t cpu_state[MAX_CPUS];
|
extern cpu_state_t cpu_state[MAX_CPUS];
|
||||||
|
|
||||||
|
extern core_type_t hybrid_core_type[MAX_CPUS];
|
||||||
|
extern bool exclude_ecores;
|
||||||
|
|
||||||
extern bool smp_enabled;
|
extern bool smp_enabled;
|
||||||
|
|
||||||
|
extern bool enable_big_status;
|
||||||
extern bool enable_temperature;
|
extern bool enable_temperature;
|
||||||
extern bool enable_trace;
|
extern bool enable_trace;
|
||||||
|
|
||||||
|
@ -62,6 +67,8 @@ extern int tty_params_port;
|
||||||
extern int tty_params_baud;
|
extern int tty_params_baud;
|
||||||
extern int tty_update_period;
|
extern int tty_update_period;
|
||||||
|
|
||||||
|
extern bool err_banner_redraw;
|
||||||
|
|
||||||
void config_init(void);
|
void config_init(void);
|
||||||
|
|
||||||
void config_menu(bool initial);
|
void config_menu(bool initial);
|
||||||
|
|
177
app/display.c
177
app/display.c
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (C) 2020-2022 Martin Whitaker.
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -21,7 +22,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "githash.h"
|
#include "build_version.h"
|
||||||
|
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
|
@ -31,13 +32,24 @@
|
||||||
// Constants
|
// Constants
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define POP_STAT_R 12
|
||||||
|
#define POP_STAT_C 18
|
||||||
|
|
||||||
|
#define POP_STAT_W 44
|
||||||
|
#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)
|
||||||
|
|
||||||
|
#define POP_STATUS_REGION POP_STAT_R, POP_STAT_C, POP_STAT_LAST_R, POP_STAT_LAST_C
|
||||||
|
|
||||||
#define SPINNER_PERIOD 100 // milliseconds
|
#define SPINNER_PERIOD 100 // milliseconds
|
||||||
|
|
||||||
#define NUM_SPIN_STATES 4
|
#define NUM_SPIN_STATES 4
|
||||||
|
|
||||||
static const char spin_state[NUM_SPIN_STATES] = { '|', '/', '-', '\\' };
|
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
|
// Private Variables
|
||||||
|
@ -60,6 +72,9 @@ static uint64_t next_spin_time = 0; // TSC time stamp
|
||||||
static int prev_sec = -1; // previous second
|
static int prev_sec = -1; // previous second
|
||||||
static bool timed_update_done = false; // update cycle status
|
static bool timed_update_done = false; // update cycle status
|
||||||
|
|
||||||
|
bool big_status_displayed = false;
|
||||||
|
static uint16_t popup_status_save_buffer[POP_STAT_W * POP_STAT_H];
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Variables
|
// Variables
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -80,49 +95,49 @@ void display_init(void)
|
||||||
|
|
||||||
clear_screen();
|
clear_screen();
|
||||||
|
|
||||||
|
/* The commented horizontal lines provide visual cue for where and how
|
||||||
|
* they will appear on the screen. They are drawn down below using
|
||||||
|
* Extended ASCII characters.
|
||||||
|
*/
|
||||||
|
|
||||||
set_foreground_colour(BLACK);
|
set_foreground_colour(BLACK);
|
||||||
set_background_colour(WHITE);
|
set_background_colour(WHITE);
|
||||||
clear_screen_region(0, 0, 0, 27);
|
clear_screen_region(0, 0, 0, 27);
|
||||||
prints(0, 0, " Memtest86+ v6.00b2");
|
prints(0, 0, " Memtest86+ v" MT_VERSION);
|
||||||
set_foreground_colour(RED);
|
set_foreground_colour(RED);
|
||||||
printc(0, 14, '+');
|
printc(0, 15, '+');
|
||||||
set_foreground_colour(WHITE);
|
set_foreground_colour(WHITE);
|
||||||
set_background_colour(BLUE);
|
set_background_colour(BLUE);
|
||||||
prints(0,28, "| ");
|
prints(1, 0, "CLK/Temp: N/A | Pass %");
|
||||||
prints(1, 0, "CLK/Temp: N/A | Pass % ");
|
prints(2, 0, "L1 Cache: N/A | Test %");
|
||||||
prints(2, 0, "L1 Cache: N/A | Test % ");
|
prints(3, 0, "L2 Cache: N/A | Test #");
|
||||||
prints(3, 0, "L2 Cache: N/A | Test # ");
|
prints(4, 0, "L3 Cache: N/A | Testing:");
|
||||||
prints(4, 0, "L3 Cache: N/A | Testing: ");
|
prints(5, 0, "Memory : N/A | Pattern:");
|
||||||
prints(5, 0, "Memory : N/A | Pattern: ");
|
// prints(6, 0, "--------------------------------------------------------------------------------");
|
||||||
prints(6, 0, "--------------------------------------------------------------------------------");
|
prints(7, 0, "CPU: SMP: N/A | Time: Status: Init.");
|
||||||
prints(7, 0, "CPU: SMP: N/A | Time: Status: Init. ");
|
prints(8, 0, "Using: | Pass: Errors:");
|
||||||
prints(8, 0, "Using: | Pass: Errors: ");
|
// prints(9, 0, "--------------------------------------------------------------------------------");
|
||||||
prints(9, 0, "--------------------------------------------------------------------------------");
|
|
||||||
|
|
||||||
// Redraw lines using box drawing characters.
|
for (int i = 0;i < 80; i++) {
|
||||||
// Disable if TTY is enabled to avoid VT100 char replacements
|
print_char(6, i, 0xc4);
|
||||||
if (!enable_tty) {
|
print_char(9, i, 0xc4);
|
||||||
for (int i = 0;i < 80; i++) {
|
|
||||||
print_char(6, i, 0xc4);
|
|
||||||
print_char(9, i, 0xc4);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
print_char(i, 28, 0xb3);
|
|
||||||
}
|
|
||||||
for (int i = 7; i < 10; i++) {
|
|
||||||
print_char(i, 42, 0xb3);
|
|
||||||
}
|
|
||||||
print_char(6, 28, 0xc1);
|
|
||||||
print_char(6, 42, 0xc2);
|
|
||||||
print_char(9, 42, 0xc1);
|
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
print_char(i, 28, 0xb3);
|
||||||
|
}
|
||||||
|
for (int i = 7; i < 10; i++) {
|
||||||
|
print_char(i, 42, 0xb3);
|
||||||
|
}
|
||||||
|
|
||||||
|
print_char(6, 28, 0xc1);
|
||||||
|
print_char(6, 42, 0xc2);
|
||||||
|
print_char(9, 42, 0xc1);
|
||||||
|
|
||||||
set_foreground_colour(BLUE);
|
set_foreground_colour(BLUE);
|
||||||
set_background_colour(WHITE);
|
set_background_colour(WHITE);
|
||||||
clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1);
|
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, 0, " <ESC> Exit <F1> Configuration <Space> Scroll Lock");
|
||||||
prints(ROW_FOOTER, 64, "6.00.");
|
prints(ROW_FOOTER, 64, MT_VERSION "." GIT_HASH);
|
||||||
prints(ROW_FOOTER, 69, GIT_HASH);
|
|
||||||
#if TESTWORD_WIDTH > 32
|
#if TESTWORD_WIDTH > 32
|
||||||
prints(ROW_FOOTER, 76, ".x64");
|
prints(ROW_FOOTER, 76, ".x64");
|
||||||
#else
|
#else
|
||||||
|
@ -178,8 +193,13 @@ void display_cpu_topology(void)
|
||||||
extern int num_enabled_cpus;
|
extern int num_enabled_cpus;
|
||||||
int num_cpu_sockets = 1;
|
int num_cpu_sockets = 1;
|
||||||
|
|
||||||
|
// Display Thread Count and Thread Dispatch Mode
|
||||||
if (smp_enabled) {
|
if (smp_enabled) {
|
||||||
display_threading(num_enabled_cpus, cpu_mode_str[cpu_mode]);
|
if (cpuid_info.topology.is_hybrid && cpuid_info.topology.ecore_count > 0 && exclude_ecores) {
|
||||||
|
display_threading(num_enabled_cpus - cpuid_info.topology.ecore_count, cpu_mode_str[cpu_mode]);
|
||||||
|
} else {
|
||||||
|
display_threading(num_enabled_cpus, cpu_mode_str[cpu_mode]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
display_threading_disabled();
|
display_threading_disabled();
|
||||||
}
|
}
|
||||||
|
@ -197,16 +217,25 @@ void display_cpu_topology(void)
|
||||||
|
|
||||||
// Compute number of sockets according to individual CPU core count
|
// Compute number of sockets according to individual CPU core count
|
||||||
if (num_enabled_cpus > cpuid_info.topology.thread_count &&
|
if (num_enabled_cpus > cpuid_info.topology.thread_count &&
|
||||||
num_enabled_cpus % cpuid_info.topology.thread_count == 0) {
|
num_enabled_cpus % cpuid_info.topology.thread_count == 0) {
|
||||||
|
|
||||||
num_cpu_sockets = num_enabled_cpus / cpuid_info.topology.thread_count;
|
num_cpu_sockets = num_enabled_cpus / cpuid_info.topology.thread_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display P/E-Core count for Hybrid CPUs.
|
||||||
// Temporary workaround for Hybrid CPUs.
|
|
||||||
// TODO: run cpuid on each core to get correct P+E topology
|
|
||||||
if (cpuid_info.topology.is_hybrid) {
|
if (cpuid_info.topology.is_hybrid) {
|
||||||
display_cpu_topo_hybrid(cpuid_info.topology.thread_count);
|
if (cpuid_info.topology.pcore_count > 1) {
|
||||||
|
|
||||||
|
if (cpuid_info.flags.htt &&
|
||||||
|
(cpuid_info.topology.thread_count - cpuid_info.topology.ecore_count) == cpuid_info.topology.pcore_count) {
|
||||||
|
cpuid_info.topology.pcore_count /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_cpu_topo_hybrid(cpuid_info.topology.pcore_count,
|
||||||
|
cpuid_info.topology.ecore_count,
|
||||||
|
cpuid_info.topology.thread_count);
|
||||||
|
} else {
|
||||||
|
display_cpu_topo_hybrid_short(cpuid_info.topology.thread_count);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +265,7 @@ void post_display_init(void)
|
||||||
if (false) {
|
if (false) {
|
||||||
// Try to get RAM information from IMC (TODO)
|
// Try to get RAM information from IMC (TODO)
|
||||||
display_spec_mode("IMC: ");
|
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;
|
display_mode = DISPLAY_MODE_IMC;
|
||||||
} else if (ram.freq > 0 && ram.tCL > 0) {
|
} else if (ram.freq > 0 && ram.tCL > 0) {
|
||||||
// If not available, grab max memory specs from SPD
|
// If not available, grab max memory specs from SPD
|
||||||
|
@ -244,7 +273,7 @@ void post_display_init(void)
|
||||||
if (ram.freq <= 166) {
|
if (ram.freq <= 166) {
|
||||||
display_spec_sdr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS);
|
display_spec_sdr(ram.freq, ram.type, ram.tCL, ram.tRCD, ram.tRP, ram.tRAS);
|
||||||
} else {
|
} 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;
|
display_mode = DISPLAY_MODE_SPD;
|
||||||
} else {
|
} else {
|
||||||
|
@ -324,9 +353,66 @@ void display_temperature(void)
|
||||||
printf(1, 20-offset, "%2i/%2i%cC", actual_cpu_temp, max_cpu_temp, 0xF8);
|
printf(1, 20-offset, "%2i/%2i%cC", actual_cpu_temp, max_cpu_temp, 0xF8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void display_big_status(bool pass)
|
||||||
|
{
|
||||||
|
if (!enable_big_status || big_status_displayed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
save_screen_region(POP_STATUS_REGION, popup_status_save_buffer);
|
||||||
|
|
||||||
|
set_background_colour(BLACK);
|
||||||
|
set_foreground_colour(pass ? GREEN : RED);
|
||||||
|
clear_screen_region(POP_STATUS_REGION);
|
||||||
|
|
||||||
|
if (pass) {
|
||||||
|
prints(POP_STAT_R+1, POP_STAT_C+5, "###### ## ##### ##### ");
|
||||||
|
prints(POP_STAT_R+2, POP_STAT_C+5, "## ## #### ## ## ## ## ");
|
||||||
|
prints(POP_STAT_R+3, POP_STAT_C+5, "## ## ## ## ## ## ");
|
||||||
|
prints(POP_STAT_R+4, POP_STAT_C+5, "###### ## ## ##### ##### ");
|
||||||
|
prints(POP_STAT_R+5, POP_STAT_C+5, "## ######## ## ## ");
|
||||||
|
prints(POP_STAT_R+6, POP_STAT_C+5, "## ## ## ## ## ## ## ");
|
||||||
|
prints(POP_STAT_R+7, POP_STAT_C+5, "## ## ## ##### ##### ");
|
||||||
|
} else {
|
||||||
|
prints(POP_STAT_R+1, POP_STAT_C+5, "####### ## ###### ## ");
|
||||||
|
prints(POP_STAT_R+2, POP_STAT_C+5, "## #### ## ## ");
|
||||||
|
prints(POP_STAT_R+3, POP_STAT_C+5, "## ## ## ## ## ");
|
||||||
|
prints(POP_STAT_R+4, POP_STAT_C+5, "##### ## ## ## ## ");
|
||||||
|
prints(POP_STAT_R+5, POP_STAT_C+5, "## ######## ## ## ");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_big_status(void)
|
||||||
|
{
|
||||||
|
if (!big_status_displayed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_screen_region(POP_STATUS_REGION, popup_status_save_buffer);
|
||||||
|
big_status_displayed = false;
|
||||||
|
}
|
||||||
|
|
||||||
void check_input(void)
|
void check_input(void)
|
||||||
{
|
{
|
||||||
switch (get_key()) {
|
char input_key = get_key();
|
||||||
|
|
||||||
|
if (input_key == '\0') {
|
||||||
|
return;
|
||||||
|
} else if (big_status_displayed) {
|
||||||
|
restore_big_status();
|
||||||
|
enable_big_status = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (input_key) {
|
||||||
case ESC:
|
case ESC:
|
||||||
clear_message_area();
|
clear_message_area();
|
||||||
display_notice("Rebooting...");
|
display_notice("Rebooting...");
|
||||||
|
@ -431,7 +517,7 @@ void do_tick(int my_cpu)
|
||||||
if (clks_per_msec > 0) {
|
if (clks_per_msec > 0) {
|
||||||
uint64_t current_time = get_tsc();
|
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 mins = secs / 60; secs %= 60; act_sec = secs;
|
||||||
int hours = mins / 60; mins %= 60;
|
int hours = mins / 60; mins %= 60;
|
||||||
display_run_time(hours, mins, secs);
|
display_run_time(hours, mins, secs);
|
||||||
|
@ -456,6 +542,11 @@ void do_tick(int my_cpu)
|
||||||
// This only tick one time per second
|
// This only tick one time per second
|
||||||
if (!timed_update_done) {
|
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
|
// Update temperature
|
||||||
display_temperature();
|
display_temperature();
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,13 @@ typedef enum {
|
||||||
#define display_threading_disabled() \
|
#define display_threading_disabled() \
|
||||||
prints(7,31, "Disabled")
|
prints(7,31, "Disabled")
|
||||||
|
|
||||||
#define display_cpu_topo_hybrid(num_threads) \
|
#define display_cpu_topo_hybrid(num_pcores, num_ecores, num_threads) \
|
||||||
|
{ \
|
||||||
|
clear_screen_region(7, 5, 7, 25); \
|
||||||
|
printf(7, 5, "%uP+%uE-Cores (%uT)", num_pcores, num_ecores, num_threads); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define display_cpu_topo_hybrid_short(num_threads) \
|
||||||
printf(7, 5, "%u Threads (Hybrid)", num_threads)
|
printf(7, 5, "%u Threads (Hybrid)", num_threads)
|
||||||
|
|
||||||
#define display_cpu_topo_multi_socket(num_sockets, num_cores, num_threads) \
|
#define display_cpu_topo_multi_socket(num_sockets, num_cores, num_threads) \
|
||||||
|
@ -96,9 +102,9 @@ typedef enum {
|
||||||
#define display_spec_mode(mode) \
|
#define display_spec_mode(mode) \
|
||||||
prints(8,0, mode);
|
prints(8,0, mode);
|
||||||
|
|
||||||
#define display_spec_ddr(freq, type, cl, rcd, rp, ras) \
|
#define display_spec_ddr(freq, type, cl, cl_dec, rcd, rp, ras) \
|
||||||
printf(8,5, "%uMHz (%s-%u) CAS %u-%u-%u-%u", \
|
printf(8,5, "%uMHz (%s-%u) CAS %u%s-%u-%u-%u", \
|
||||||
freq / 2, type, freq, cl, rcd, rp, ras);
|
freq / 2, type, freq, cl, cl_dec?".5":"", rcd, rp, ras);
|
||||||
|
|
||||||
#define display_spec_sdr(freq, type, cl, 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", \
|
printf(8,5, "%uMHz (%s PC%u) CAS %u-%u-%u-%u", \
|
||||||
|
@ -194,10 +200,10 @@ typedef enum {
|
||||||
printf(scroll_message_row, col, __VA_ARGS__)
|
printf(scroll_message_row, col, __VA_ARGS__)
|
||||||
|
|
||||||
#define display_notice(str) \
|
#define display_notice(str) \
|
||||||
prints(ROW_MESSAGE_T + 6, (SCREEN_WIDTH - strlen(str)) / 2, str)
|
prints(ROW_MESSAGE_T + 8, (SCREEN_WIDTH - strlen(str)) / 2, str)
|
||||||
|
|
||||||
#define display_notice_with_args(length, ...) \
|
#define display_notice_with_args(length, ...) \
|
||||||
printf(ROW_MESSAGE_T + 6, (SCREEN_WIDTH - length) / 2, __VA_ARGS__)
|
printf(ROW_MESSAGE_T + 8, (SCREEN_WIDTH - length) / 2, __VA_ARGS__)
|
||||||
|
|
||||||
#define clear_footer_message() \
|
#define clear_footer_message() \
|
||||||
{ \
|
{ \
|
||||||
|
@ -234,6 +240,10 @@ void display_start_test(void);
|
||||||
|
|
||||||
void display_temperature(void);
|
void display_temperature(void);
|
||||||
|
|
||||||
|
void display_big_status(bool pass);
|
||||||
|
|
||||||
|
void restore_big_status(void);
|
||||||
|
|
||||||
void check_input(void);
|
void check_input(void);
|
||||||
|
|
||||||
void set_scroll_lock(bool enabled);
|
void set_scroll_lock(bool enabled);
|
||||||
|
|
|
@ -151,6 +151,8 @@ static void common_err(error_type_t type, uintptr_t addr, testword_t good, testw
|
||||||
{
|
{
|
||||||
spin_lock(error_mutex);
|
spin_lock(error_mutex);
|
||||||
|
|
||||||
|
restore_big_status();
|
||||||
|
|
||||||
bool new_header = (error_count == 0) || (error_mode != last_error_mode);
|
bool new_header = (error_count == 0) || (error_mode != last_error_mode);
|
||||||
if (new_header) {
|
if (new_header) {
|
||||||
clear_message_area();
|
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)
|
void data_error(testword_t *addr, testword_t good, testword_t bad, bool use_for_badram)
|
||||||
{
|
{
|
||||||
#if USB_WORKAROUND
|
#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
|
* 0x4e0 for USB keyboard support. This often happens with Intel
|
||||||
* 810, 815 and 820 chipsets. It is possible that we will skip
|
* 810, 815 and 820 chipsets. It is possible that we will skip
|
||||||
* a real error but the odds are very low.
|
* a real error but the odds are very low.
|
||||||
|
@ -369,6 +371,11 @@ void error_update(void)
|
||||||
display_error_count(error_count);
|
display_error_count(error_count);
|
||||||
display_status("Failed!");
|
display_status("Failed!");
|
||||||
|
|
||||||
|
// Display FAIL banner on first error
|
||||||
|
if (error_count == 1) {
|
||||||
|
display_big_status(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (enable_tty) {
|
if (enable_tty) {
|
||||||
tty_error_redraw();
|
tty_error_redraw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,7 +196,7 @@ void interrupt(struct trap_regs *trap_regs)
|
||||||
|
|
||||||
clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1);
|
clear_screen_region(ROW_FOOTER, 0, ROW_FOOTER, SCREEN_WIDTH - 1);
|
||||||
prints(ROW_FOOTER, 0, "Press any key to reboot...");
|
prints(ROW_FOOTER, 0, "Press any key to reboot...");
|
||||||
|
|
||||||
while (get_key() == 0) { }
|
while (get_key() == 0) { }
|
||||||
reboot();
|
reboot();
|
||||||
}
|
}
|
||||||
|
|
57
app/main.c
57
app/main.c
|
@ -4,8 +4,8 @@
|
||||||
// Derived from memtest86+ main.c:
|
// Derived from memtest86+ main.c:
|
||||||
//
|
//
|
||||||
// MemTest86+ V5 Specific code (GPL V2.0)
|
// MemTest86+ V5 Specific code (GPL V2.0)
|
||||||
// By Samuel DEMEULEMEESTER, sdemeule@memtest.org
|
// By Samuel DEMEULEMEESTER, memtest@memtest.org
|
||||||
// http://www.canardpc.com - http://www.memtest.org
|
// https://www.memtest.org
|
||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// main.c - MemTest-86 Version 3.5
|
// main.c - MemTest-86 Version 3.5
|
||||||
//
|
//
|
||||||
|
@ -18,9 +18,11 @@
|
||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
#include "bootparams.h"
|
#include "bootparams.h"
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
#include "cpuinfo.h"
|
#include "cpuinfo.h"
|
||||||
|
#include "heap.h"
|
||||||
#include "hwctrl.h"
|
#include "hwctrl.h"
|
||||||
#include "hwquirks.h"
|
#include "hwquirks.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
@ -33,6 +35,7 @@
|
||||||
#include "smbios.h"
|
#include "smbios.h"
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
#include "temperature.h"
|
#include "temperature.h"
|
||||||
|
#include "timers.h"
|
||||||
#include "vmem.h"
|
#include "vmem.h"
|
||||||
|
|
||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
|
@ -214,14 +217,20 @@ static void global_init(void)
|
||||||
|
|
||||||
pmem_init();
|
pmem_init();
|
||||||
|
|
||||||
|
heap_init();
|
||||||
|
|
||||||
pci_init();
|
pci_init();
|
||||||
|
|
||||||
|
quirks_init();
|
||||||
|
|
||||||
|
acpi_init();
|
||||||
|
|
||||||
|
timers_init();
|
||||||
|
|
||||||
membw_init();
|
membw_init();
|
||||||
|
|
||||||
smbios_init();
|
smbios_init();
|
||||||
|
|
||||||
quirks_init();
|
|
||||||
|
|
||||||
badram_init();
|
badram_init();
|
||||||
|
|
||||||
config_init();
|
config_init();
|
||||||
|
@ -242,10 +251,16 @@ static void global_init(void)
|
||||||
|
|
||||||
error_init();
|
error_init();
|
||||||
|
|
||||||
|
temperature_init();
|
||||||
|
|
||||||
initial_config();
|
initial_config();
|
||||||
|
|
||||||
clear_message_area();
|
clear_message_area();
|
||||||
|
|
||||||
|
if (!smp_enabled) {
|
||||||
|
num_available_cpus = 1;
|
||||||
|
}
|
||||||
|
|
||||||
num_enabled_cpus = 0;
|
num_enabled_cpus = 0;
|
||||||
for (int i = 0; i < num_available_cpus; i++) {
|
for (int i = 0; i < num_available_cpus; i++) {
|
||||||
if (cpu_state[i] == CPU_STATE_ENABLED) {
|
if (cpu_state[i] == CPU_STATE_ENABLED) {
|
||||||
|
@ -278,8 +293,9 @@ static void global_init(void)
|
||||||
for (int i = 0; i < pm_map_size; i++) {
|
for (int i = 0; i < pm_map_size; i++) {
|
||||||
trace(0, "pm %0*x - %0*x", 2*sizeof(uintptr_t), pm_map[i].start, 2*sizeof(uintptr_t), pm_map[i].end);
|
trace(0, "pm %0*x - %0*x", 2*sizeof(uintptr_t), pm_map[i].start, 2*sizeof(uintptr_t), pm_map[i].end);
|
||||||
}
|
}
|
||||||
if (rsdp_addr != 0) {
|
if (acpi_config.rsdp_addr != 0) {
|
||||||
trace(0, "ACPI RSDP found in %s at %0*x", rsdp_source, 2*sizeof(uintptr_t), rsdp_addr);
|
trace(0, "ACPI RSDP (v%u.%u) found in %s at %0*x", acpi_config.ver_maj, acpi_config.ver_min, rsdp_source, 2*sizeof(uintptr_t), acpi_config.rsdp_addr);
|
||||||
|
trace(0, "ACPI FADT found at %0*x", 2*sizeof(uintptr_t), acpi_config.fadt_addr);
|
||||||
}
|
}
|
||||||
if (!load_addr_ok) {
|
if (!load_addr_ok) {
|
||||||
trace(0, "Cannot relocate program. Press any key to reboot...");
|
trace(0, "Cannot relocate program. Press any key to reboot...");
|
||||||
|
@ -297,6 +313,30 @@ static void global_init(void)
|
||||||
restart = false;
|
restart = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ap_enumerate(int my_cpu)
|
||||||
|
{
|
||||||
|
if (!cpuid_info.topology.is_hybrid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hybrid_core_type[my_cpu] = get_ap_hybrid_type();
|
||||||
|
|
||||||
|
if (hybrid_core_type[my_cpu] == CORE_PCORE) {
|
||||||
|
cpuid_info.topology.pcore_count++;
|
||||||
|
} else if (hybrid_core_type[my_cpu] == CORE_ECORE) {
|
||||||
|
cpuid_info.topology.ecore_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hybrid_core_type[my_cpu] == CORE_ECORE && exclude_ecores) {
|
||||||
|
cpu_state[my_cpu] = CPU_STATE_DISABLED;
|
||||||
|
//TODO : hlt AP?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_cpu == num_enabled_cpus - 1) {
|
||||||
|
display_cpu_topology();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void setup_vm_map(uintptr_t win_start, uintptr_t win_end)
|
static void setup_vm_map(uintptr_t win_start, uintptr_t win_end)
|
||||||
{
|
{
|
||||||
vm_map_size = 0;
|
vm_map_size = 0;
|
||||||
|
@ -496,6 +536,7 @@ void main(void)
|
||||||
} else {
|
} else {
|
||||||
trace(my_cpu, "AP started");
|
trace(my_cpu, "AP started");
|
||||||
cpu_state[my_cpu] = CPU_STATE_RUNNING;
|
cpu_state[my_cpu] = CPU_STATE_RUNNING;
|
||||||
|
ap_enumerate(my_cpu);
|
||||||
while (init_state < 2) {
|
while (init_state < 2) {
|
||||||
usleep(100);
|
usleep(100);
|
||||||
}
|
}
|
||||||
|
@ -629,7 +670,9 @@ void main(void)
|
||||||
display_pass_count(pass_num);
|
display_pass_count(pass_num);
|
||||||
if (error_count == 0) {
|
if (error_count == 0) {
|
||||||
display_status("Pass ");
|
display_status("Pass ");
|
||||||
display_notice("** Pass completed, no errors **");
|
display_big_status(true);
|
||||||
|
} 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 <stdint.h>
|
||||||
|
|
||||||
|
#include <boot.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t orig_x;
|
uint8_t orig_x;
|
||||||
uint8_t orig_y;
|
uint8_t orig_y;
|
||||||
|
@ -56,6 +58,7 @@ typedef struct {
|
||||||
|
|
||||||
#define VIDEO_TYPE_VLFB 0x23 // VESA VGA in graphic mode
|
#define VIDEO_TYPE_VLFB 0x23 // VESA VGA in graphic mode
|
||||||
#define VIDEO_TYPE_EFI 0x70 // EFI 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)
|
#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);
|
efi_graphics_output_t *gop = find_gop(handles, handles_size);
|
||||||
if (!gop) {
|
if (!gop) {
|
||||||
#if DEBUG
|
print_string("No graphics display found\n");
|
||||||
print_string("GOP not found\n");
|
|
||||||
#endif
|
|
||||||
return EFI_NOT_FOUND;
|
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);
|
efi_call_bs(free_pool, info);
|
||||||
}
|
}
|
||||||
if (best_mode == UINT32_MAX) {
|
if (best_mode == UINT32_MAX) {
|
||||||
#if DEBUG
|
print_string("No suitable screen resolution found\n");
|
||||||
print_string("No suitable GOP screen resolution\n");
|
|
||||||
#endif
|
|
||||||
return EFI_NOT_FOUND;
|
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);
|
status = efi_call_proto(gop, set_mode, best_mode);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
#if DEBUG
|
|
||||||
print_string("Set GOP mode failed\n");
|
print_string("Set GOP mode failed\n");
|
||||||
#endif
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,7 +496,16 @@ static efi_status_t set_screen_info(boot_params_t *boot_params)
|
||||||
if (status == EFI_SUCCESS) {
|
if (status == EFI_SUCCESS) {
|
||||||
status = set_screen_info_from_gop(&boot_params->screen_info, handles, handles_size);
|
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);
|
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;
|
return status;
|
||||||
|
@ -559,7 +562,7 @@ static efi_status_t set_efi_info_and_exit_boot_services(efi_handle_t handle, boo
|
||||||
boot_params->efi_info.mem_desc_version = mem_desc_version;
|
boot_params->efi_info.mem_desc_version = mem_desc_version;
|
||||||
boot_params->efi_info.mem_map = (uintptr_t)mem_map;
|
boot_params->efi_info.mem_map = (uintptr_t)mem_map;
|
||||||
boot_params->efi_info.mem_map_size = mem_map_size;
|
boot_params->efi_info.mem_map_size = mem_map_size;
|
||||||
#ifdef __X86_64__
|
#ifdef __x86_64__
|
||||||
boot_params->efi_info.sys_tab_hi = (uintptr_t)sys_table >> 32;
|
boot_params->efi_info.sys_tab_hi = (uintptr_t)sys_table >> 32;
|
||||||
boot_params->efi_info.mem_map_hi = (uintptr_t)mem_map >> 32;
|
boot_params->efi_info.mem_map_hi = (uintptr_t)mem_map >> 32;
|
||||||
#endif
|
#endif
|
||||||
|
@ -571,7 +574,7 @@ fail:
|
||||||
static void set_e820_map(boot_params_t *params)
|
static void set_e820_map(boot_params_t *params)
|
||||||
{
|
{
|
||||||
uintptr_t mem_map_addr = params->efi_info.mem_map;
|
uintptr_t mem_map_addr = params->efi_info.mem_map;
|
||||||
#ifdef __X86_64__
|
#ifdef __x86_64__
|
||||||
mem_map_addr |= (uintptr_t)params->efi_info.mem_map_hi << 32;
|
mem_map_addr |= (uintptr_t)params->efi_info.mem_map_hi << 32;
|
||||||
#endif
|
#endif
|
||||||
size_t mem_map_size = params->efi_info.mem_map_size;
|
size_t mem_map_size = params->efi_info.mem_map_size;
|
||||||
|
|
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
|
// end of the boot sector), with the remainder of the header being provided by
|
||||||
// setup.S.
|
// setup.S.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2020 Martin Whitaker.
|
// Copyright (C) 2020-2023 Martin Whitaker.
|
||||||
//
|
//
|
||||||
// Derived from Linux 5.6 arch/x86/boot/header.S:
|
// Derived from Linux 5.6 arch/x86/boot/header.S:
|
||||||
//
|
//
|
||||||
|
@ -21,13 +21,13 @@
|
||||||
#define __ASSEMBLY__
|
#define __ASSEMBLY__
|
||||||
|
|
||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
|
#include "peimage.h"
|
||||||
|
|
||||||
# The EFI loader loads the header at ImageBase, so we have to locate the main program
|
# 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
|
# 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.
|
# address well away from HIGH_LOAD_ADDR, to avoid overlap when relocating the code.
|
||||||
|
|
||||||
#define IMAGE_BASE 0x200000
|
#define IMAGE_BASE 0x200000
|
||||||
#define BASE_OF_CODE 0x1000
|
|
||||||
|
|
||||||
.section ".header", "ax", @progbits
|
.section ".header", "ax", @progbits
|
||||||
.code16
|
.code16
|
||||||
|
@ -85,50 +85,46 @@ pe_header:
|
||||||
|
|
||||||
coff_header:
|
coff_header:
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
.word 0x8664 # Machine (x86-64)
|
.word IMAGE_FILE_MACHINE_X64 # Machine (x86-64)
|
||||||
#else
|
#else
|
||||||
.word 0x14c # Machine (i386)
|
.word IMAGE_FILE_MACHINE_I386 # Machine (i386)
|
||||||
#endif
|
#endif
|
||||||
.word 1 # NumberOfSections
|
.word 3 # NumberOfSections
|
||||||
.long 0 # TimeDateStamp
|
.long 0 # TimeDateStamp
|
||||||
.long 0 # PointerToSymbolTable
|
.long 0 # PointerToSymbolTable
|
||||||
.long 0 # NumberOfSymbols
|
.long 0 # NumberOfSymbols
|
||||||
.word section_table - optional_header # SizeOfOptionalHeader
|
.word section_table - optional_header # SizeOfOptionalHeader
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
.word 0x20f # Characteristics
|
.word IMAGE_FILE_DEBUG_STRIPPED \
|
||||||
# IMAGE_FILE_DEBUG_STRIPPED |
|
| IMAGE_FILE_LOCAL_SYMS_STRIPPED \
|
||||||
# IMAGE_FILE_LOCAL_SYMS_STRIPPED |
|
| IMAGE_FILE_LINE_NUMS_STRIPPED \
|
||||||
# IMAGE_FILE_LINE_NUMS_STRIPPED |
|
| IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics
|
||||||
# IMAGE_FILE_EXECUTABLE_IMAGE |
|
|
||||||
# IMAGE_FILE_RELOCS_STRIPPED
|
|
||||||
#else
|
#else
|
||||||
.word 0x30f # Characteristics.
|
.word IMAGE_FILE_32BIT_MACHINE \
|
||||||
# IMAGE_FILE_32BIT_MACHINE |
|
| IMAGE_FILE_DEBUG_STRIPPED \
|
||||||
# IMAGE_FILE_DEBUG_STRIPPED |
|
| IMAGE_FILE_LOCAL_SYMS_STRIPPED \
|
||||||
# IMAGE_FILE_LOCAL_SYMS_STRIPPED |
|
| IMAGE_FILE_LINE_NUMS_STRIPPED \
|
||||||
# IMAGE_FILE_LINE_NUMS_STRIPPED |
|
| IMAGE_FILE_EXECUTABLE_IMAGE # Characteristics.
|
||||||
# IMAGE_FILE_EXECUTABLE_IMAGE |
|
|
||||||
# IMAGE_FILE_RELOCS_STRIPPED
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
optional_header:
|
optional_header:
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
.word 0x20b # PE32+ format
|
.word IMAGE_NT_OPTIONAL_HDR64_MAGIC # PE32+ format
|
||||||
#else
|
#else
|
||||||
.word 0x10b # PE32 format
|
.word IMAGE_NT_OPTIONAL_HDR32_MAGIC # PE32 format
|
||||||
#endif
|
#endif
|
||||||
.byte 0x02 # MajorLinkerVersion
|
.byte 0x02 # MajorLinkerVersion
|
||||||
.byte 0x14 # MinorLinkerVersion
|
.byte 0x14 # MinorLinkerVersion
|
||||||
|
|
||||||
.long _text_size # SizeOfCode
|
.long _virt_text_size # SizeOfCode
|
||||||
.long 0 # SizeOfInitializedData
|
.long _virt_sbat_size # SizeOfInitializedData
|
||||||
.long 0 # SizeOfUninitializedData
|
.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__
|
#ifndef __x86_64__
|
||||||
.long 0 # data
|
.long _virt_sbat_start # BaseOfData
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extra_header_fields:
|
extra_header_fields:
|
||||||
|
@ -147,8 +143,8 @@ extra_header_fields:
|
||||||
.word 0 # MinorSubsystemVersion
|
.word 0 # MinorSubsystemVersion
|
||||||
.long 0 # Win32VersionValue
|
.long 0 # Win32VersionValue
|
||||||
|
|
||||||
.long BASE_OF_CODE + _init_size # SizeOfImage
|
.long _virt_img_size # SizeOfImage
|
||||||
.long 512 # SizeOfHeaders
|
.long _file_head_size # SizeOfHeaders
|
||||||
.long 0 # CheckSum
|
.long 0 # CheckSum
|
||||||
.word 10 # Subsystem (EFI application)
|
.word 10 # Subsystem (EFI application)
|
||||||
.word 0 # DllCharacteristics
|
.word 0 # DllCharacteristics
|
||||||
|
@ -164,7 +160,20 @@ extra_header_fields:
|
||||||
.long 0 # SizeOfHeapCommit
|
.long 0 # SizeOfHeapCommit
|
||||||
#endif
|
#endif
|
||||||
.long 0 # LoaderFlags
|
.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
|
||||||
section_table:
|
section_table:
|
||||||
|
@ -172,15 +181,46 @@ section_table:
|
||||||
.byte 0
|
.byte 0
|
||||||
.byte 0
|
.byte 0
|
||||||
.byte 0
|
.byte 0
|
||||||
.long _text_size # VirtualSize
|
.long _virt_text_size # VirtualSize
|
||||||
.long BASE_OF_CODE # VirtualAddress
|
.long _virt_text_start # VirtualAddress
|
||||||
.long _text_size # SizeOfRawData
|
.long _file_text_size # SizeOfRawData
|
||||||
.long _text_start # PointerToRawData
|
.long _file_text_start # PointerToRawData
|
||||||
.long 0 # PointerToRelocations
|
.long 0 # PointerToRelocations
|
||||||
.long 0 # PointerToLineNumbers
|
.long 0 # PointerToLineNumbers
|
||||||
.word 0 # NumberOfRelocations
|
.word 0 # NumberOfRelocations
|
||||||
.word 0 # NumberOfLineNumbers
|
.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.
|
# Emulate the Linux boot header, to allow loading by intermediate boot loaders.
|
||||||
|
|
||||||
|
@ -199,3 +239,13 @@ root_dev:
|
||||||
.word 0
|
.word 0
|
||||||
boot_flag:
|
boot_flag:
|
||||||
.word 0xAA55
|
.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
|
|
11
boot/setup.S
11
boot/setup.S
|
@ -18,6 +18,7 @@
|
||||||
#define __ASSEMBLY__
|
#define __ASSEMBLY__
|
||||||
|
|
||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
|
#include "build_version.h"
|
||||||
|
|
||||||
#define BOOT_PARAMS_START (SETUP_SECS * 512)
|
#define BOOT_PARAMS_START (SETUP_SECS * 512)
|
||||||
#define BOOT_PARAMS_END (BOOT_PARAMS_START + 4096)
|
#define BOOT_PARAMS_END (BOOT_PARAMS_START + 4096)
|
||||||
|
@ -41,7 +42,7 @@ realmode_swtch:
|
||||||
start_sys_seg:
|
start_sys_seg:
|
||||||
.word 0x1000
|
.word 0x1000
|
||||||
kernel_version:
|
kernel_version:
|
||||||
.word 0
|
.word mt86plus_version-512
|
||||||
type_of_loader:
|
type_of_loader:
|
||||||
.byte 0
|
.byte 0
|
||||||
loadflags:
|
loadflags:
|
||||||
|
@ -132,7 +133,7 @@ do_setup:
|
||||||
call empty_8042
|
call empty_8042
|
||||||
movb $0xd1, %al # send write command
|
movb $0xd1, %al # send write command
|
||||||
outb %al, $0x64
|
outb %al, $0x64
|
||||||
call empty_8042
|
call empty_8042
|
||||||
movb $0xdf, %al # A20 on
|
movb $0xdf, %al # A20 on
|
||||||
outb %al, $0x60
|
outb %al, $0x60
|
||||||
call empty_8042
|
call empty_8042
|
||||||
|
@ -352,7 +353,7 @@ empty_8042:
|
||||||
call delay
|
call delay
|
||||||
inb $0x60, %al # read it
|
inb $0x60, %al # read it
|
||||||
jmp empty_8042
|
jmp empty_8042
|
||||||
|
|
||||||
no_output:
|
no_output:
|
||||||
testb $2, %al # is input buffer full?
|
testb $2, %al # is input buffer full?
|
||||||
jnz empty_8042 # yes - loop
|
jnz empty_8042 # yes - loop
|
||||||
|
@ -385,6 +386,10 @@ idt_descr:
|
||||||
.word 0 # idt limit=0
|
.word 0 # idt limit=0
|
||||||
.long 0 # idt base=0
|
.long 0 # idt base=0
|
||||||
|
|
||||||
|
mt86plus_version:
|
||||||
|
.ascii "Memtest86+ v" , MT_VERSION
|
||||||
|
.byte 0
|
||||||
|
|
||||||
# Pad to the declared size.
|
# Pad to the declared size.
|
||||||
|
|
||||||
.org (SETUP_SECS*512)
|
.org (SETUP_SECS*512)
|
||||||
|
|
|
@ -812,7 +812,7 @@ startup_stack_top:
|
||||||
|
|
||||||
# Main stack area.
|
# Main stack area.
|
||||||
|
|
||||||
.section "stacks", "aw", @progbits
|
.section ".stacks", "aw", @nobits
|
||||||
.align 16
|
.align 16
|
||||||
|
|
||||||
. = . + STACKS_SIZE
|
. = . + STACKS_SIZE
|
||||||
|
|
|
@ -14,11 +14,13 @@ CFLAGS = -std=c11 -Wall -Wextra -Wshadow -m32 -march=i586 -fpic -fno-builtin \
|
||||||
|
|
||||||
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
||||||
|
|
||||||
SYS_OBJS = system/cpuid.o \
|
SYS_OBJS = system/acpi.o \
|
||||||
|
system/cpuid.o \
|
||||||
system/cpuinfo.o \
|
system/cpuinfo.o \
|
||||||
system/cpulocal.o \
|
system/cpulocal.o \
|
||||||
system/ehci.o \
|
system/ehci.o \
|
||||||
system/font.o \
|
system/font.o \
|
||||||
|
system/heap.o \
|
||||||
system/hwctrl.o \
|
system/hwctrl.o \
|
||||||
system/hwquirks.o \
|
system/hwquirks.o \
|
||||||
system/keyboard.o \
|
system/keyboard.o \
|
||||||
|
@ -32,6 +34,7 @@ SYS_OBJS = system/cpuid.o \
|
||||||
system/smbus.o \
|
system/smbus.o \
|
||||||
system/smp.o \
|
system/smp.o \
|
||||||
system/temperature.o \
|
system/temperature.o \
|
||||||
|
system/timers.o \
|
||||||
system/uhci.o \
|
system/uhci.o \
|
||||||
system/usbhcd.o \
|
system/usbhcd.o \
|
||||||
system/vmem.o \
|
system/vmem.o \
|
||||||
|
@ -72,16 +75,15 @@ all: memtest.bin memtest.efi
|
||||||
-include $(subst .o,.d,$(TST_OBJS))
|
-include $(subst .o,.d,$(TST_OBJS))
|
||||||
-include $(subst .o,.d,$(APP_OBJS))
|
-include $(subst .o,.d,$(APP_OBJS))
|
||||||
|
|
||||||
boot/%.o: boot/%.s
|
boot/header.o : | ../boot/sbat.csv
|
||||||
$(AS) $< -o $@
|
|
||||||
|
|
||||||
boot/startup.s: ../boot/startup32.S ../boot/boot.h
|
boot/startup.o: ../boot/startup32.S ../boot/boot.h
|
||||||
@mkdir -p boot
|
@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
|
@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
|
boot/efisetup.o: ../boot/efisetup.c
|
||||||
@mkdir -p boot
|
@mkdir -p boot
|
||||||
|
@ -103,20 +105,22 @@ tests/%.o: ../tests/%.c
|
||||||
@mkdir -p tests
|
@mkdir -p tests
|
||||||
$(CC) -c $(CFLAGS) -O3 $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
$(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
|
@mkdir -p app
|
||||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
$(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
|
@mkdir -p app
|
||||||
@( \
|
@( \
|
||||||
|
cp -f ../app/version.h $@.tmp; \
|
||||||
if $(GIT_AVAILABLE) && test -d ../.git ; then \
|
if $(GIT_AVAILABLE) && test -d ../.git ; then \
|
||||||
hash=`git rev-parse HEAD | cut -c1-7`; \
|
hash=`git rev-parse HEAD | cut -c1-7`; \
|
||||||
|
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "'$$hash'"/' $@.tmp; \
|
||||||
else \
|
else \
|
||||||
hash="unknown"; \
|
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "unknown"/' $@.tmp; \
|
||||||
fi; \
|
fi; \
|
||||||
define=`echo "#define GIT_HASH \"$$hash\""`; \
|
cmp $@ $@.tmp 2>/dev/null || cp -f $@.tmp $@; \
|
||||||
echo $$define | diff - $@ > /dev/null 2>&1 || echo $$define > $@; \
|
rm -f $@.tmp; \
|
||||||
)
|
)
|
||||||
|
|
||||||
FORCE:
|
FORCE:
|
||||||
|
@ -166,8 +170,13 @@ iso: memtest.iso
|
||||||
clean:
|
clean:
|
||||||
rm -rf boot system lib tests app *.img *.iso memtest* iso grub-*
|
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,
|
# grub-memtest.iso uses GRUB as an intermediate bootloader to allow Memtest86+
|
||||||
# using GRUB as an intermediate bootloader. Upstream GRUB only supports the
|
# 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.
|
# 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"
|
# Fedora add support for the EFI handover boot protocols, via the "linuxefi"
|
||||||
# command, and, since 2019, remove support for the 32-bit protocol, aliasing
|
# command, and, since 2019, remove support for the 32-bit protocol, aliasing
|
||||||
|
@ -177,6 +186,8 @@ clean:
|
||||||
# doubt do their own thing. The boot menu on grub-memtest.iso attempts to
|
# doubt do their own thing. The boot menu on grub-memtest.iso attempts to
|
||||||
# support all these options.
|
# support all these options.
|
||||||
|
|
||||||
|
GRUB_CFG ?= grub
|
||||||
|
|
||||||
GRUB_FONT_DIR ?= /usr/share/grub
|
GRUB_FONT_DIR ?= /usr/share/grub
|
||||||
|
|
||||||
GRUB_LIB_DIR ?= /usr/lib/grub
|
GRUB_LIB_DIR ?= /usr/lib/grub
|
||||||
|
@ -192,22 +203,22 @@ grub-eltorito.img:
|
||||||
grub-bootia32.efi:
|
grub-bootia32.efi:
|
||||||
$(GRUB_MKIMAGE) --output $@ --prefix /EFI/BOOT/grub --format i386-efi $(GRUB_MODULES)
|
$(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
|
@mkdir -p grub-iso/EFI/BOOT/grub/i386-efi grub-iso/EFI/BOOT/grub/fonts
|
||||||
cp memtest.efi grub-iso/EFI/BOOT/memtest
|
cp memtest.efi grub-iso/EFI/BOOT/memtest
|
||||||
cp grub-bootia32.efi grub-iso/EFI/BOOT/bootia32.efi
|
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_FONT_DIR)/unicode.pf2 grub-iso/EFI/BOOT/grub/fonts/
|
||||||
cp $(GRUB_LIB_DIR)/i386-efi/*.mod grub-iso/EFI/BOOT/grub/i386-efi/
|
cp $(GRUB_LIB_DIR)/i386-efi/*.mod grub-iso/EFI/BOOT/grub/i386-efi/
|
||||||
@rm -f grub-esp.img
|
@rm -f grub-esp.img
|
||||||
/sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192
|
/sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192
|
||||||
mcopy -s -i grub-esp.img grub-iso/EFI ::
|
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
|
@mkdir -p grub-iso/boot/grub/i386-pc grub-iso/boot/grub/fonts
|
||||||
cp memtest.bin grub-iso/boot/memtest
|
cp memtest.bin grub-iso/boot/memtest
|
||||||
cp grub-eltorito.img grub-iso/boot/eltorito.img
|
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_FONT_DIR)/unicode.pf2 grub-iso/boot/grub/fonts/
|
||||||
cp $(GRUB_LIB_DIR)/i386-pc/*.mod grub-iso/boot/grub/i386-pc/
|
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 \
|
xorrisofs -pad -R -J -volid MT86PLUS_32 -graft-points -hide-rr-moved \
|
||||||
|
|
|
@ -12,15 +12,48 @@ SECTIONS {
|
||||||
}
|
}
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
.text : {
|
.text : {
|
||||||
_text_start = . ;
|
_file_text_start = . ;
|
||||||
*(.data)
|
*(.data)
|
||||||
|
_real_text_end = . ;
|
||||||
. = ALIGN(512);
|
. = 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/ : { *(*) }
|
/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;
|
_file_head_size = _file_text_start;
|
||||||
_init_size = _text_size + _bss_size;
|
_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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,14 @@ CFLAGS = -std=c11 -Wall -Wextra -Wshadow -m64 -march=x86-64 -mno-mmx -mno-sse -m
|
||||||
|
|
||||||
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
INC_DIRS = -I../boot -I../system -I../lib -I../tests -I../app -Iapp
|
||||||
|
|
||||||
SYS_OBJS = system/cpuid.o \
|
SYS_OBJS = system/acpi.o \
|
||||||
|
system/cpuid.o \
|
||||||
system/cpuinfo.o \
|
system/cpuinfo.o \
|
||||||
system/cpulocal.o \
|
system/cpulocal.o \
|
||||||
system/ehci.o \
|
system/ehci.o \
|
||||||
system/font.o \
|
system/font.o \
|
||||||
system/hwctrl.o \
|
system/hwctrl.o \
|
||||||
|
system/heap.o \
|
||||||
system/hwquirks.o \
|
system/hwquirks.o \
|
||||||
system/keyboard.o \
|
system/keyboard.o \
|
||||||
system/ohci.o \
|
system/ohci.o \
|
||||||
|
@ -32,6 +34,7 @@ SYS_OBJS = system/cpuid.o \
|
||||||
system/smbus.o \
|
system/smbus.o \
|
||||||
system/smp.o \
|
system/smp.o \
|
||||||
system/temperature.o \
|
system/temperature.o \
|
||||||
|
system/timers.o \
|
||||||
system/uhci.o \
|
system/uhci.o \
|
||||||
system/usbhcd.o \
|
system/usbhcd.o \
|
||||||
system/vmem.o \
|
system/vmem.o \
|
||||||
|
@ -71,16 +74,15 @@ all: memtest.bin memtest.efi
|
||||||
-include $(subst .o,.d,$(TST_OBJS))
|
-include $(subst .o,.d,$(TST_OBJS))
|
||||||
-include $(subst .o,.d,$(APP_OBJS))
|
-include $(subst .o,.d,$(APP_OBJS))
|
||||||
|
|
||||||
boot/%.o: boot/%.s
|
boot/header.o : | ../boot/sbat.csv
|
||||||
$(AS) $< -o $@
|
|
||||||
|
|
||||||
boot/startup.s: ../boot/startup64.S ../boot/boot.h
|
boot/startup.o: ../boot/startup64.S ../boot/boot.h
|
||||||
@mkdir -p boot
|
@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
|
@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
|
boot/efisetup.o: ../boot/efisetup.c
|
||||||
@mkdir -p boot
|
@mkdir -p boot
|
||||||
|
@ -102,20 +104,22 @@ tests/%.o: ../tests/%.c
|
||||||
@mkdir -p tests
|
@mkdir -p tests
|
||||||
$(CC) -c $(CFLAGS) -O3 $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
$(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
|
@mkdir -p app
|
||||||
$(CC) -c $(CFLAGS) -Os $(INC_DIRS) -o $@ $< -MMD -MP -MT $@ -MF $(@:.o=.d)
|
$(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
|
@mkdir -p app
|
||||||
@( \
|
@( \
|
||||||
|
cp -f ../app/version.h $@.tmp; \
|
||||||
if $(GIT_AVAILABLE) && test -d ../.git ; then \
|
if $(GIT_AVAILABLE) && test -d ../.git ; then \
|
||||||
hash=`git rev-parse HEAD | cut -c1-7`; \
|
hash=`git rev-parse HEAD | cut -c1-7`; \
|
||||||
|
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "'$$hash'"/' $@.tmp; \
|
||||||
else \
|
else \
|
||||||
hash="unknown"; \
|
sed -i 's/GIT_HASH\s\".*"/GIT_HASH "unknown"/' $@.tmp; \
|
||||||
fi; \
|
fi; \
|
||||||
define=`echo "#define GIT_HASH \"$$hash\""`; \
|
cmp $@ $@.tmp 2>/dev/null || cp -f $@.tmp $@; \
|
||||||
echo $$define | diff - $@ > /dev/null 2>&1 || echo $$define > $@; \
|
rm -f $@.tmp; \
|
||||||
)
|
)
|
||||||
|
|
||||||
FORCE:
|
FORCE:
|
||||||
|
@ -165,8 +169,13 @@ iso: memtest.iso
|
||||||
clean:
|
clean:
|
||||||
rm -rf boot system lib tests app *.img *.iso memtest* iso grub-*
|
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,
|
# grub-memtest.iso uses GRUB as an intermediate bootloader to allow Memtest86+
|
||||||
# using GRUB as an intermediate bootloader. Upstream GRUB only supports the
|
# 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.
|
# 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"
|
# Fedora add support for the EFI handover boot protocols, via the "linuxefi"
|
||||||
# command, and, since 2019, remove support for the 32-bit protocol, aliasing
|
# command, and, since 2019, remove support for the 32-bit protocol, aliasing
|
||||||
|
@ -176,6 +185,8 @@ clean:
|
||||||
# doubt do their own thing. The boot menu on grub-memtest.iso attempts to
|
# doubt do their own thing. The boot menu on grub-memtest.iso attempts to
|
||||||
# support all these options.
|
# support all these options.
|
||||||
|
|
||||||
|
GRUB_CFG ?= grub
|
||||||
|
|
||||||
GRUB_FONT_DIR ?= /usr/share/grub
|
GRUB_FONT_DIR ?= /usr/share/grub
|
||||||
|
|
||||||
GRUB_LIB_DIR ?= /usr/lib/grub
|
GRUB_LIB_DIR ?= /usr/lib/grub
|
||||||
|
@ -191,22 +202,22 @@ grub-eltorito.img:
|
||||||
grub-bootx64.efi:
|
grub-bootx64.efi:
|
||||||
$(GRUB_MKIMAGE) --output $@ --prefix /EFI/BOOT/grub --format x86_64-efi $(GRUB_MODULES)
|
$(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
|
@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 memtest.efi grub-iso/EFI/BOOT/memtest
|
||||||
cp grub-bootx64.efi grub-iso/EFI/BOOT/bootx64.efi
|
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_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/
|
cp $(GRUB_LIB_DIR)/x86_64-efi/*.mod grub-iso/EFI/BOOT/grub/x86_64-efi/
|
||||||
@rm -f grub-esp.img
|
@rm -f grub-esp.img
|
||||||
/sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192
|
/sbin/mkdosfs -n MT86P_ESP -F12 -C grub-esp.img 8192
|
||||||
mcopy -s -i grub-esp.img grub-iso/EFI ::
|
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
|
@mkdir -p grub-iso/boot/grub/i386-pc grub-iso/boot/grub/fonts
|
||||||
cp memtest.bin grub-iso/boot/memtest
|
cp memtest.bin grub-iso/boot/memtest
|
||||||
cp grub-eltorito.img grub-iso/boot/eltorito.img
|
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_FONT_DIR)/unicode.pf2 grub-iso/boot/grub/fonts/
|
||||||
cp $(GRUB_LIB_DIR)/i386-pc/*.mod grub-iso/boot/grub/i386-pc/
|
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 \
|
xorrisofs -pad -R -J -volid MT86PLUS_64 -graft-points -hide-rr-moved \
|
||||||
|
|
|
@ -12,15 +12,48 @@ SECTIONS {
|
||||||
}
|
}
|
||||||
. = ALIGN(512);
|
. = ALIGN(512);
|
||||||
.text : {
|
.text : {
|
||||||
_text_start = . ;
|
_file_text_start = . ;
|
||||||
*(.data)
|
*(.data)
|
||||||
|
_real_text_end = . ;
|
||||||
. = ALIGN(512);
|
. = 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/ : { *(*) }
|
/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;
|
_file_head_size = _file_text_start;
|
||||||
_init_size = _text_size + _bss_size;
|
_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
|
set timeout=-1
|
||||||
|
|
||||||
insmod linux
|
insmod linux
|
||||||
insmod linuxefi
|
|
||||||
insmod linux32
|
|
||||||
|
|
||||||
menuentry "Start Memtest86+ using 'linux' command" {
|
menuentry "Start Memtest86+, use built-in support for USB keyboards" {
|
||||||
linux /EFI/BOOT/memtest
|
linux /EFI/BOOT/memtest keyboard=both
|
||||||
}
|
}
|
||||||
menuentry "Start Memtest86+ using 'linuxefi' command" {
|
menuentry "Start Memtest86+, use BIOS legacy emulation for USB keyboards" {
|
||||||
linuxefi /EFI/BOOT/memtest
|
linux /EFI/BOOT/memtest keyboard=legacy
|
||||||
}
|
}
|
||||||
menuentry "Start Memtest86+ using 'linux32' command" {
|
menuentry "Start Memtest86+, disable SMP and memory identification" {
|
||||||
linux32 /EFI/BOOT/memtest
|
linux /EFI/BOOT/memtest nosmp nosm nobench
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,13 @@ set default=0
|
||||||
set timeout=-1
|
set timeout=-1
|
||||||
|
|
||||||
insmod linux
|
insmod linux
|
||||||
insmod linux16
|
|
||||||
insmod linux32
|
|
||||||
|
|
||||||
menuentry "Start Memtest86+ using 'linux' command" {
|
menuentry "Start Memtest86+, use built-in support for USB keyboards" {
|
||||||
linux /boot/memtest
|
linux /boot/memtest keyboard=both
|
||||||
}
|
}
|
||||||
menuentry "Start Memtest86+ using 'linux16' command" {
|
menuentry "Start Memtest86+, use BIOS legacy emulation for USB keyboards" {
|
||||||
linux16 /boot/memtest
|
linux /boot/memtest keyboard=legacy
|
||||||
}
|
}
|
||||||
menuentry "Start Memtest86+ using 'linux32' command" {
|
menuentry "Start Memtest86+, disable SMP and memory identification" {
|
||||||
linux32 /boot/memtest
|
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
|
// 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)
|
void *memmove(void *dest, const void *src, size_t n)
|
||||||
{
|
{
|
||||||
char *d = (char *)dest, *s = (char *)src;
|
char *d = (char *)dest, *s = (char *)src;
|
||||||
|
@ -64,28 +52,6 @@ void *memmove(void *dest, const void *src, size_t n)
|
||||||
return dest;
|
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)
|
char *strstr(const char *haystack, const char *needle)
|
||||||
{
|
{
|
||||||
size_t haystack_len = strlen(haystack);
|
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
|
* between the first mismatching byte in s1 (interpreted as an unsigned
|
||||||
* value) and the corresponding byte in s2.
|
* 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
|
* 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.
|
* 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
|
* 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
|
* between the first mismatching character in s1 (interpreted as a signed
|
||||||
* value) and the corresponding character in s2.
|
* 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
|
* Finds the first occurrence of the substring needle in the string haystack
|
||||||
|
|
344
system/acpi.c
Normal file
344
system/acpi.c
Normal file
|
@ -0,0 +1,344 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
|
|
||||||
|
#include "boot.h"
|
||||||
|
#include "bootparams.h"
|
||||||
|
#include "efi.h"
|
||||||
|
|
||||||
|
#include "pmem.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "unistd.h"
|
||||||
|
#include "vmem.h"
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Table signatures
|
||||||
|
|
||||||
|
#define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
|
||||||
|
#define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24))
|
||||||
|
|
||||||
|
#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24)) // Root System Description Table
|
||||||
|
|
||||||
|
#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24)) // Extended System Description Table
|
||||||
|
|
||||||
|
#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24)) // Multiple APIC Description Table
|
||||||
|
|
||||||
|
#define FADTSignature ('F' | ('A' << 8) | ('C' << 16) | ('P' << 24)) // Fixed ACPI Description Table
|
||||||
|
|
||||||
|
#define HPETSignature ('H' | ('P' << 8) | ('E' << 16) | ('T' << 24)) // High Precision Event Timer
|
||||||
|
|
||||||
|
#define EINJSignature ('E' | ('I' << 8) | ('N' << 16) | ('J' << 24)) // Error Injection Table
|
||||||
|
#define ERSTSignature ('E' | ('R' << 8) | ('S' << 16) | ('T' << 24)) // Error Record Serialization Table
|
||||||
|
#define CPEPSignature ('C' | ('P' << 8) | ('E' << 16) | ('P' << 24)) // Corrected Platform Error Polling Table
|
||||||
|
#define HESTSignature ('H' | ('E' << 8) | ('S' << 16) | ('T' << 24)) // Hardware Error Source Table
|
||||||
|
|
||||||
|
#define SLITSignature ('S' | ('L' << 8) | ('I' << 16) | ('T' << 24)) // System Locality Information Table (NUMA)
|
||||||
|
#define SRATSignature ('S' | ('R' << 8) | ('A' << 16) | ('T' << 24)) // System Resource Affinity Table (NUMA)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef struct __attribute__ ((packed)) {
|
||||||
|
uint8_t address_space;
|
||||||
|
uint8_t bit_width;
|
||||||
|
uint8_t bit_offset;
|
||||||
|
uint8_t access_size;
|
||||||
|
uint64_t address;
|
||||||
|
} acpi_gen_addr_struct;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char signature[8]; // "RSD PTR "
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_addr;
|
||||||
|
uint32_t length;
|
||||||
|
uint64_t xsdt_addr;
|
||||||
|
uint8_t xchecksum;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} rsdp_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char signature[4]; // "RSDT" or "XSDT"
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
char oem_table_id[8];
|
||||||
|
char oem_revision[4];
|
||||||
|
char creator_id[4];
|
||||||
|
char creator_revision[4];
|
||||||
|
} rsdt_header_t;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Private Variables
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static const efi_guid_t EFI_ACPI_1_RDSP_GUID = { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} };
|
||||||
|
static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} };
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Variables
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const char *rsdp_source = "";
|
||||||
|
|
||||||
|
acpi_t acpi_config = {0, 0, 0, 0, 0, 0, 0, false};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Private Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static rsdp_t *scan_for_rsdp(uintptr_t addr, int length)
|
||||||
|
{
|
||||||
|
uint32_t *ptr = (uint32_t *)addr;
|
||||||
|
uint32_t *end = ptr + length / sizeof(uint32_t);
|
||||||
|
|
||||||
|
while (ptr < end) {
|
||||||
|
rsdp_t *rp = (rsdp_t *)ptr;
|
||||||
|
if (*ptr == RSDPSignature1 && *(ptr+1) == RSDPSignature2 && acpi_checksum(ptr, 20) == 0) {
|
||||||
|
if (rp->revision < 2 || (rp->length < 1024 && acpi_checksum(ptr, rp->length) == 0)) {
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
static rsdp_t *find_rsdp_in_efi64_system_table(efi64_system_table_t *system_table)
|
||||||
|
{
|
||||||
|
efi64_config_table_t *config_tables = (efi64_config_table_t *)map_region(system_table->config_tables,
|
||||||
|
system_table->num_config_tables * sizeof(efi64_config_table_t),
|
||||||
|
true);
|
||||||
|
if (config_tables == NULL) return NULL;
|
||||||
|
|
||||||
|
uintptr_t table_addr = 0;
|
||||||
|
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (rsdp_t *)table_addr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static rsdp_t *find_rsdp_in_efi32_system_table(efi32_system_table_t *system_table)
|
||||||
|
{
|
||||||
|
efi32_config_table_t *config_tables = (efi32_config_table_t *)map_region(system_table->config_tables,
|
||||||
|
system_table->num_config_tables * sizeof(efi32_config_table_t),
|
||||||
|
true);
|
||||||
|
if (config_tables == NULL) return NULL;
|
||||||
|
|
||||||
|
uintptr_t table_addr = 0;
|
||||||
|
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
||||||
|
table_addr = config_tables[i].table;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (rsdp_t *)table_addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uintptr_t find_rsdp(void)
|
||||||
|
{
|
||||||
|
const boot_params_t *boot_params = (boot_params_t *)boot_params_addr;
|
||||||
|
|
||||||
|
const efi_info_t *efi_info = &boot_params->efi_info;
|
||||||
|
|
||||||
|
// Search for the RSDP
|
||||||
|
rsdp_t *rp = NULL;
|
||||||
|
#ifdef __x86_64__
|
||||||
|
if (efi_info->loader_signature == EFI64_LOADER_SIGNATURE) {
|
||||||
|
uintptr_t system_table_addr = (uintptr_t)efi_info->sys_tab_hi << 32 | (uintptr_t)efi_info->sys_tab;
|
||||||
|
system_table_addr = map_region(system_table_addr, sizeof(efi64_system_table_t), true);
|
||||||
|
if (system_table_addr != 0) {
|
||||||
|
rp = find_rsdp_in_efi64_system_table((efi64_system_table_t *)system_table_addr);
|
||||||
|
if (rp) rsdp_source = "EFI64 system table";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (efi_info->loader_signature == EFI32_LOADER_SIGNATURE) {
|
||||||
|
uintptr_t system_table_addr = map_region(efi_info->sys_tab, sizeof(efi32_system_table_t), true);
|
||||||
|
if (system_table_addr != 0) {
|
||||||
|
rp = find_rsdp_in_efi32_system_table((efi32_system_table_t *)system_table_addr);
|
||||||
|
if (rp) rsdp_source = "EFI32 system table";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (rp == NULL) {
|
||||||
|
// Search the BIOS EBDA area.
|
||||||
|
uintptr_t address = *(uint16_t *)0x40E << 4;
|
||||||
|
if (address) {
|
||||||
|
rp = scan_for_rsdp(address, 0x400);
|
||||||
|
if (rp) rsdp_source = "BIOS EBDA";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rp == NULL) {
|
||||||
|
// Search the BIOS reserved area.
|
||||||
|
rp = scan_for_rsdp(0xE0000, 0x20000);
|
||||||
|
if (rp) rsdp_source = "BIOS reserved area";
|
||||||
|
}
|
||||||
|
if (rp == NULL) {
|
||||||
|
// RSDP not found, give up.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (uintptr_t)rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uintptr_t find_acpi_table(uint32_t table_signature)
|
||||||
|
{
|
||||||
|
rsdp_t *rp = (rsdp_t *)acpi_config.rsdp_addr;
|
||||||
|
|
||||||
|
// Found the RSDP, now get either the RSDT or XSDT
|
||||||
|
// and scan it for a pointer to the table we're looking for
|
||||||
|
rsdt_header_t *rt;
|
||||||
|
|
||||||
|
if (acpi_config.ver_maj < rp->revision) {
|
||||||
|
acpi_config.ver_maj = rp->revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rp->revision >= 2) {
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, sizeof(rsdt_header_t), true);
|
||||||
|
if (rt == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Validate the XSDT.
|
||||||
|
if (*(uint32_t *)rt != XSDTSignature) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, rt->length, true);
|
||||||
|
if (rt == NULL || acpi_checksum(rt, rt->length) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Scan the XSDT for a pointer to the table we're looking for.
|
||||||
|
uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
||||||
|
uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length);
|
||||||
|
|
||||||
|
while (tab_ptr < tab_end) {
|
||||||
|
uintptr_t addr = *tab_ptr++; // read the next table entry
|
||||||
|
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
||||||
|
|
||||||
|
if (ptr && *ptr == table_signature) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, sizeof(rsdt_header_t), true);
|
||||||
|
if (rt == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Validate the RSDT.
|
||||||
|
if (*(uint32_t *)rt != RSDTSignature) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, rt->length, true);
|
||||||
|
if (rt == NULL || acpi_checksum(rt, rt->length) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Scan the RSDT for a pointer to the table we're looking for.
|
||||||
|
uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
||||||
|
uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length);
|
||||||
|
|
||||||
|
while (tab_ptr < tab_end) {
|
||||||
|
uintptr_t addr = *tab_ptr++; // read the next table entry
|
||||||
|
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
||||||
|
|
||||||
|
if (ptr && *ptr == table_signature) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_fadt(uintptr_t fadt_addr)
|
||||||
|
{
|
||||||
|
// FADT is a very big & complex table and we only need a few data.
|
||||||
|
// We use byte offset instead of a complete struct.
|
||||||
|
|
||||||
|
// FADT Header is identical to RSDP Header
|
||||||
|
rsdt_header_t *fadt = (rsdt_header_t *)fadt_addr;
|
||||||
|
|
||||||
|
// Validate FADT
|
||||||
|
if (fadt == NULL || acpi_checksum(fadt, fadt->length) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ACPI Version
|
||||||
|
acpi_config.ver_maj = fadt->revision;
|
||||||
|
|
||||||
|
if (fadt->length > FADT_MINOR_REV_OFFSET) {
|
||||||
|
acpi_config.ver_min = *(uint8_t *)(fadt_addr+FADT_MINOR_REV_OFFSET) & 0xF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Old PM Base Address (32bit IO)
|
||||||
|
acpi_config.pm_addr = *(uint32_t *)(fadt_addr+FADT_PM_TMR_BLK_OFFSET);
|
||||||
|
acpi_config.pm_is_io = true;
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
acpi_gen_addr_struct *rt;
|
||||||
|
|
||||||
|
// Get APIC Timer Address
|
||||||
|
if (fadt->length > FADT_X_PM_TMR_BLK_OFFSET) {
|
||||||
|
rt = (acpi_gen_addr_struct *)map_region(fadt_addr+FADT_X_PM_TMR_BLK_OFFSET, sizeof(acpi_gen_addr_struct), true);
|
||||||
|
|
||||||
|
acpi_config.pm_is_io = (rt->address_space == 1) ? true : false;
|
||||||
|
|
||||||
|
if (rt->address != 0) {
|
||||||
|
acpi_config.pm_addr = rt->address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Public Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int acpi_checksum(const void *data, int length)
|
||||||
|
{
|
||||||
|
uint8_t sum = 0;
|
||||||
|
|
||||||
|
uint8_t *ptr = (uint8_t *)data;
|
||||||
|
while (length--) {
|
||||||
|
sum += *ptr++;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void acpi_init(void)
|
||||||
|
{
|
||||||
|
acpi_config.rsdp_addr = find_rsdp();
|
||||||
|
|
||||||
|
if (acpi_config.rsdp_addr == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acpi_config.madt_addr = find_acpi_table(MADTSignature);
|
||||||
|
|
||||||
|
acpi_config.fadt_addr = find_acpi_table(FADTSignature);
|
||||||
|
|
||||||
|
if (acpi_config.fadt_addr) {
|
||||||
|
parse_fadt(acpi_config.fadt_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
acpi_config.hpet_addr = find_acpi_table(HPETSignature);
|
||||||
|
}
|
57
system/acpi.h
Normal file
57
system/acpi.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#ifndef _ACPI_H_
|
||||||
|
#define _ACPI_H_
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* Provides support for ACPI (Find & parse tables)
|
||||||
|
*
|
||||||
|
*//*
|
||||||
|
* Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
* Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FADT_PM_TMR_BLK_OFFSET 76
|
||||||
|
#define FADT_MINOR_REV_OFFSET 131
|
||||||
|
#define FADT_X_PM_TMR_BLK_OFFSET 208
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A struct containing various ACPI-related infos for later uses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct __attribute__ ((packed)) {
|
||||||
|
uint8_t ver_maj;
|
||||||
|
uint8_t ver_min;
|
||||||
|
uintptr_t rsdp_addr;
|
||||||
|
uintptr_t madt_addr;
|
||||||
|
uintptr_t fadt_addr;
|
||||||
|
uintptr_t hpet_addr;
|
||||||
|
uintptr_t pm_addr;
|
||||||
|
bool pm_is_io;
|
||||||
|
} acpi_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The search step that located the ACPI RSDP (for debug).
|
||||||
|
*/
|
||||||
|
extern const char *rsdp_source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global ACPI config struct
|
||||||
|
*/
|
||||||
|
extern acpi_t acpi_config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACPI Table Checksum Function
|
||||||
|
*/
|
||||||
|
int acpi_checksum(const void *data, int length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look for specific ACPI Tables Addresses (RSDP, MADT, ...)
|
||||||
|
* and parse some of the tables
|
||||||
|
*/
|
||||||
|
void acpi_init(void);
|
||||||
|
|
||||||
|
#endif /* _ACPI_H_ */
|
|
@ -46,7 +46,7 @@ static inline void cache_on(void)
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
__asm__ __volatile__ ("\t"
|
__asm__ __volatile__ ("\t"
|
||||||
"movq %%cr0, %%rax \n\t"
|
"movq %%cr0, %%rax \n\t"
|
||||||
"andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */
|
"andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */
|
||||||
"movq %%rax, %%cr0 \n"
|
"movq %%rax, %%cr0 \n"
|
||||||
: /* no outputs */
|
: /* no outputs */
|
||||||
: /* no inputs */
|
: /* no inputs */
|
||||||
|
@ -55,7 +55,7 @@ static inline void cache_on(void)
|
||||||
#else
|
#else
|
||||||
__asm__ __volatile__ ("\t"
|
__asm__ __volatile__ ("\t"
|
||||||
"movl %%cr0, %%eax \n\t"
|
"movl %%cr0, %%eax \n\t"
|
||||||
"andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */
|
"andl $0x9fffffff, %%eax \n\t" /* Clear CD and NW */
|
||||||
"movl %%eax, %%cr0 \n"
|
"movl %%eax, %%cr0 \n"
|
||||||
: /* no outputs */
|
: /* no outputs */
|
||||||
: /* no inputs */
|
: /* no inputs */
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
// Derived from memtest86+ cpuid.h
|
// Derived from memtest86+ cpuid.h
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
|
@ -36,7 +36,7 @@ void cpuid_init(void)
|
||||||
// Get the processor family information & feature flags.
|
// Get the processor family information & feature flags.
|
||||||
if (cpuid_info.max_cpuid >= 1) {
|
if (cpuid_info.max_cpuid >= 1) {
|
||||||
cpuid(0x1, 0,
|
cpuid(0x1, 0,
|
||||||
&cpuid_info.version.raw,
|
&cpuid_info.version.raw[0],
|
||||||
&cpuid_info.proc_info.raw,
|
&cpuid_info.proc_info.raw,
|
||||||
&cpuid_info.flags.raw[1],
|
&cpuid_info.flags.raw[1],
|
||||||
&cpuid_info.flags.raw[0]
|
&cpuid_info.flags.raw[0]
|
||||||
|
@ -65,8 +65,8 @@ void cpuid_init(void)
|
||||||
if (cpuid_info.max_xcpuid >= 0x80000001) {
|
if (cpuid_info.max_xcpuid >= 0x80000001) {
|
||||||
cpuid(0x80000001, 0,
|
cpuid(0x80000001, 0,
|
||||||
®[0],
|
®[0],
|
||||||
|
&cpuid_info.version.raw[1],
|
||||||
®[1],
|
®[1],
|
||||||
®[2],
|
|
||||||
&cpuid_info.flags.raw[2]
|
&cpuid_info.flags.raw[2]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -108,30 +108,21 @@ void cpuid_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get cache information.
|
// Get cache information.
|
||||||
switch (cpuid_info.vendor_id.str[0]) {
|
if (cpuid_info.max_xcpuid >= 0x80000005) {
|
||||||
case 'A':
|
cpuid(0x80000005, 0,
|
||||||
// AMD Processors
|
®[0],
|
||||||
if (cpuid_info.max_xcpuid >= 0x80000005) {
|
®[1],
|
||||||
cpuid(0x80000005, 0,
|
&cpuid_info.cache_info.raw[0],
|
||||||
®[0],
|
&cpuid_info.cache_info.raw[1]
|
||||||
®[1],
|
);
|
||||||
&cpuid_info.cache_info.raw[0],
|
}
|
||||||
&cpuid_info.cache_info.raw[1]
|
if (cpuid_info.max_xcpuid >= 0x80000006) {
|
||||||
);
|
cpuid(0x80000006, 0,
|
||||||
}
|
®[0],
|
||||||
if (cpuid_info.max_xcpuid >= 0x80000006) {
|
®[1],
|
||||||
cpuid(0x80000006, 0,
|
&cpuid_info.cache_info.raw[2],
|
||||||
®[0],
|
&cpuid_info.cache_info.raw[3]
|
||||||
®[1],
|
);
|
||||||
&cpuid_info.cache_info.raw[2],
|
|
||||||
&cpuid_info.cache_info.raw[3]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
// Intel Processors
|
|
||||||
// No cpuid info to read.
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect CPU Topology (Core/Thread) infos
|
// Detect CPU Topology (Core/Thread) infos
|
||||||
|
@ -176,20 +167,27 @@ void cpuid_init(void)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
// VIA / CentaurHauls
|
// Cyrix / VIA / CentaurHauls / Zhaoxin
|
||||||
|
cpuid_info.flags.htt = false;
|
||||||
break;
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
if (cpuid_info.vendor_id.str[7] == 'T') break; // Transmeta
|
if (cpuid_info.vendor_id.str[7] == 'T') break; // Transmeta
|
||||||
// Intel
|
// Intel
|
||||||
if (cpuid_info.max_cpuid >= 0xB) {
|
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+
|
// Populate Hybrid Status (CPUID 7.EDX[15]) for Alder Lake+
|
||||||
cpuid(0x7, 0, ®[0], ®[1], ®[2], ®[3]);
|
cpuid(0x7, 0, ®[0], ®[1], ®[2], ®[3]);
|
||||||
if (reg[3] & (1 << 15)) {
|
if (reg[3] & (1 << 15)) {
|
||||||
cpuid_info.topology.is_hybrid = 1;
|
cpuid_info.topology.is_hybrid = 1;
|
||||||
|
cpuid_info.topology.pcore_count = 1; // We have at least 1 P-Core as BSP
|
||||||
|
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]);
|
cpuid(0xB, i, ®[0], ®[1], ®[2], ®[3]);
|
||||||
|
|
||||||
switch((reg[2] >> 8) & 0xFF) {
|
switch((reg[2] >> 8) & 0xFF) {
|
||||||
|
@ -213,7 +211,11 @@ void cpuid_init(void)
|
||||||
cpuid_info.topology.thread_count = cpuid_info.topology.core_count;
|
cpuid_info.topology.thread_count = cpuid_info.topology.core_count;
|
||||||
|
|
||||||
if (cpuid_info.flags.htt){
|
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) {
|
} else if (cpuid_info.max_cpuid >= 0x2) {
|
||||||
if(cpuid_info.flags.htt){
|
if(cpuid_info.flags.htt){
|
||||||
|
@ -226,3 +228,19 @@ void cpuid_init(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core_type_t get_ap_hybrid_type(void)
|
||||||
|
{
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
|
||||||
|
cpuid(0x1A, 0, &eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
|
switch ((eax >> 24) & 0xFF) {
|
||||||
|
case CPU_PCORE_ID:
|
||||||
|
return CORE_PCORE;
|
||||||
|
case CPU_ECORE_ID:
|
||||||
|
return CORE_ECORE;
|
||||||
|
default:
|
||||||
|
return CORE_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,12 +15,21 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define CPU_ECORE_ID 0x20
|
||||||
|
#define CPU_PCORE_ID 0x40
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CORE_UNKNOWN,
|
||||||
|
CORE_PCORE,
|
||||||
|
CORE_ECORE
|
||||||
|
} core_type_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structures that hold the collected CPUID information.
|
* Structures that hold the collected CPUID information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
uint32_t raw;
|
uint32_t raw[2];
|
||||||
struct {
|
struct {
|
||||||
uint32_t stepping : 4;
|
uint32_t stepping : 4;
|
||||||
uint32_t model : 4;
|
uint32_t model : 4;
|
||||||
|
@ -30,6 +39,7 @@ typedef union {
|
||||||
uint32_t extendedModel : 4;
|
uint32_t extendedModel : 4;
|
||||||
uint32_t extendedFamily : 8;
|
uint32_t extendedFamily : 8;
|
||||||
uint32_t : 4;
|
uint32_t : 4;
|
||||||
|
uint32_t extendedBrandID : 32; // AMD Only
|
||||||
};
|
};
|
||||||
} cpuid_version_t;
|
} cpuid_version_t;
|
||||||
|
|
||||||
|
@ -113,7 +123,7 @@ typedef union {
|
||||||
} cpuid_brand_string_t;
|
} cpuid_brand_string_t;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
uint32_t raw[12];
|
uint32_t raw[4];
|
||||||
struct {
|
struct {
|
||||||
uint32_t : 24;
|
uint32_t : 24;
|
||||||
uint32_t l1_i_size : 8;
|
uint32_t l1_i_size : 8;
|
||||||
|
@ -194,6 +204,11 @@ extern cpuid_info_t cpuid_info;
|
||||||
*/
|
*/
|
||||||
void cpuid_init(void);
|
void cpuid_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Core Type (for Hybrid CPUs)
|
||||||
|
*/
|
||||||
|
core_type_t get_ap_hybrid_type(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the cpuid instruction.
|
* Executes the cpuid instruction.
|
||||||
*/
|
*/
|
||||||
|
|
207
system/cpuinfo.c
207
system/cpuinfo.c
|
@ -25,6 +25,7 @@
|
||||||
#include "pmem.h"
|
#include "pmem.h"
|
||||||
#include "vmem.h"
|
#include "vmem.h"
|
||||||
#include "memsize.h"
|
#include "memsize.h"
|
||||||
|
#include "hwquirks.h"
|
||||||
|
|
||||||
#include "cpuinfo.h"
|
#include "cpuinfo.h"
|
||||||
|
|
||||||
|
@ -32,7 +33,6 @@
|
||||||
// Constants
|
// Constants
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#define PIT_TICKS_50mS 59659 // PIT clock is 1.193182MHz
|
|
||||||
#define BENCH_MIN_START_ADR 0x1000000 // 16MB
|
#define BENCH_MIN_START_ADR 0x1000000 // 16MB
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -71,12 +71,45 @@ static void determine_cache_size()
|
||||||
l3_cache *= 512;
|
l3_cache *= 512;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
// Zhaoxin CPU only
|
if (cpuid_info.vendor_id.str[5] == 'I') {
|
||||||
if (cpuid_info.version.family != 7) {
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
|
// Zhaoxin CPU only
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 'G':
|
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
|
// Intel Processors
|
||||||
l1_cache = 0;
|
l1_cache = 0;
|
||||||
l2_cache = 0;
|
l2_cache = 0;
|
||||||
|
@ -296,10 +329,12 @@ static void determine_imc(void)
|
||||||
imc_type = IMC_K18; // Hygon (Family 18h)
|
imc_type = IMC_K18; // Hygon (Family 18h)
|
||||||
break;
|
break;
|
||||||
case 0xA:
|
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)
|
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 {
|
} else {
|
||||||
imc_type = IMC_K19; // Zen3 & Zen4 (Family 19h)
|
imc_type = IMC_K19; // Zen3 (Family 19h)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -458,6 +493,9 @@ static void determine_imc(void)
|
||||||
case 0x9:
|
case 0x9:
|
||||||
imc_type = IMC_KBL; // Core 7/8/9th Gen (Kaby/Coffee/Comet Lake)
|
imc_type = IMC_KBL; // Core 7/8/9th Gen (Kaby/Coffee/Comet Lake)
|
||||||
break;
|
break;
|
||||||
|
case 0xB:
|
||||||
|
imc_type = IMC_ADL_N; // Core 12th Gen (Alder Lake-N - Gracemont E-Cores only)
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -597,9 +635,9 @@ static void determine_cpu_model(void)
|
||||||
// Transmeta Processors - vendor_id starts with "GenuineTMx86"
|
// Transmeta Processors - vendor_id starts with "GenuineTMx86"
|
||||||
if (cpuid_info.vendor_id.str[7] == 'T' ) {
|
if (cpuid_info.vendor_id.str[7] == 'T' ) {
|
||||||
if (cpuid_info.version.family == 5) {
|
if (cpuid_info.version.family == 5) {
|
||||||
cpu_model = "TM 5x00";
|
cpu_model = "Transmeta TM 5x00";
|
||||||
} else if (cpuid_info.version.family == 15) {
|
} 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;
|
l1_cache = cpuid_info.cache_info.l1_i_size + cpuid_info.cache_info.l1_d_size;
|
||||||
l2_cache = cpuid_info.cache_info.l2_size;
|
l2_cache = cpuid_info.cache_info.l2_size;
|
||||||
|
@ -645,14 +683,14 @@ static void determine_cpu_model(void)
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
case 7:
|
case 7:
|
||||||
cpu_model = "Pentium";
|
cpu_model = "Intel Pentium";
|
||||||
if (l1_cache == 0) {
|
if (l1_cache == 0) {
|
||||||
l1_cache = 8;
|
l1_cache = 8;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
cpu_model = "Pentium-MMX";
|
cpu_model = "Intel Pentium MMX";
|
||||||
if (l1_cache == 0) {
|
if (l1_cache == 0) {
|
||||||
l1_cache = 16;
|
l1_cache = 16;
|
||||||
}
|
}
|
||||||
|
@ -665,54 +703,54 @@ static void determine_cpu_model(void)
|
||||||
switch (cpuid_info.version.model) {
|
switch (cpuid_info.version.model) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
cpu_model = "Pentium Pro";
|
cpu_model = "Intel Pentium Pro";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
cpu_model = "Pentium II";
|
cpu_model = "Intel Pentium II";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (l2_cache == 0) {
|
if (l2_cache == 0) {
|
||||||
cpu_model = "Celeron";
|
cpu_model = "Intel Celeron";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Pentium II";
|
cpu_model = "Intel Pentium II";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (l2_cache == 128) {
|
if (l2_cache == 128) {
|
||||||
cpu_model = "Celeron";
|
cpu_model = "Intel Celeron";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Pentium II";
|
cpu_model = "Intel Pentium II";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
case 8:
|
case 8:
|
||||||
case 11:
|
case 11:
|
||||||
if (l2_cache == 128) {
|
if (l2_cache == 128) {
|
||||||
cpu_model = "Celeron";
|
cpu_model = "Intel Celeron";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Pentium III";
|
cpu_model = "Intel Pentium III";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
if (l2_cache == 512) {
|
if (l2_cache == 512) {
|
||||||
cpu_model = "Celeron M (0.13)";
|
cpu_model = "Intel Celeron M (0.13)";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Pentium M (0.13)";
|
cpu_model = "Intel Pentium M (0.13)";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
cpu_model = "Pentium III Xeon";
|
cpu_model = "Intel Pentium III Xeon";
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
l1_cache = 24;
|
l1_cache = 24;
|
||||||
cpu_model = "Atom (0.045)";
|
cpu_model = "Intel Atom (0.045)";
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
if (l2_cache == 1024) {
|
if (l2_cache == 1024) {
|
||||||
cpu_model = "Celeron M (0.09)";
|
cpu_model = "Intel Celeron M (0.09)";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Pentium M (0.09)";
|
cpu_model = "Intel Pentium M (0.09)";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
|
@ -720,7 +758,7 @@ static void determine_cpu_model(void)
|
||||||
break;
|
break;
|
||||||
case 15:
|
case 15:
|
||||||
if (l2_cache == 1024) {
|
if (l2_cache == 1024) {
|
||||||
cpu_model = "Pentium E";
|
cpu_model = "Intel Pentium E";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Intel Core 2";
|
cpu_model = "Intel Core 2";
|
||||||
}
|
}
|
||||||
|
@ -735,17 +773,17 @@ static void determine_cpu_model(void)
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
if (l2_cache == 128) {
|
if (l2_cache == 128) {
|
||||||
cpu_model = "Celeron";
|
cpu_model = "Intel Celeron";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Pentium 4";
|
cpu_model = "Intel Pentium 4";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
if (l2_cache == 256) {
|
if (l2_cache == 256) {
|
||||||
cpu_model = "Celeron (0.09)";
|
cpu_model = "Intel Celeron (0.09)";
|
||||||
} else {
|
} else {
|
||||||
cpu_model = "Pentium 4 (0.09)";
|
cpu_model = "Intel Pentium 4 (0.09)";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
|
@ -765,78 +803,40 @@ static void determine_cpu_model(void)
|
||||||
// VIA/Cyrix/Centaur Processors with CPUID
|
// VIA/Cyrix/Centaur Processors with CPUID
|
||||||
if (cpuid_info.vendor_id.str[1] == 'e' ) {
|
if (cpuid_info.vendor_id.str[1] == 'e' ) {
|
||||||
// CentaurHauls
|
// 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) {
|
switch (cpuid_info.version.family) {
|
||||||
case 5:
|
case 5:
|
||||||
cpu_model = "Centaur 5x86";
|
cpu_model = "IDT WinChip C6";
|
||||||
|
l1_cache = 32;
|
||||||
|
// WinChip 2/3 (models 8/9) have brand string
|
||||||
break;
|
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:
|
default:
|
||||||
|
// All VIA/Centaur family values >= 6 have brand string
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else { /* CyrixInstead */
|
} else { /* CyrixInstead */
|
||||||
switch (cpuid_info.version.family) {
|
switch (cpuid_info.version.family) {
|
||||||
case 5:
|
case 4:
|
||||||
switch (cpuid_info.version.model) {
|
switch (cpuid_info.version.model) {
|
||||||
case 0:
|
case 2:
|
||||||
cpu_model = "Cyrix 6x86MX/MII";
|
cpu_model = "Cyrix 5x86";
|
||||||
|
l1_cache = 16;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
cpu_model = "Cyrix GXm";
|
cpu_model = "Cyrix MediaGX/GXi";
|
||||||
|
l1_cache = 16;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6: // VIA C3
|
case 5:
|
||||||
switch (cpuid_info.version.model) {
|
cpu_model = "Cyrix 6x86/6x86L";
|
||||||
case 6:
|
l1_cache = 16;
|
||||||
cpu_model = "Cyrix III";
|
// Media GXm (model 4) has brand string
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 6:
|
||||||
if (cpuid_info.version.stepping < 8) {
|
cpu_model = "Cyrix 6x86MX/MII";
|
||||||
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
|
|
||||||
l1_cache = 64;
|
l1_cache = 64;
|
||||||
l2_cache = 64;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -847,10 +847,10 @@ static void determine_cpu_model(void)
|
||||||
// Unknown processor - make a guess at the family.
|
// Unknown processor - make a guess at the family.
|
||||||
switch (cpuid_info.version.family) {
|
switch (cpuid_info.version.family) {
|
||||||
case 5:
|
case 5:
|
||||||
cpu_model = "586";
|
cpu_model = "586-class CPU (unknown)";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
cpu_model = "686";
|
cpu_model = "686-class CPU (unknown)";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cpu_model = "Unidentified Processor";
|
cpu_model = "Unidentified Processor";
|
||||||
|
@ -860,37 +860,6 @@ static void determine_cpu_model(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void measure_cpu_speed(void)
|
|
||||||
{
|
|
||||||
if (cpuid_info.flags.rdtsc == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up timer
|
|
||||||
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
|
|
||||||
outb(0xb0, 0x43);
|
|
||||||
outb(PIT_TICKS_50mS & 0xff, 0x42);
|
|
||||||
outb(PIT_TICKS_50mS >> 8, 0x42);
|
|
||||||
|
|
||||||
uint32_t start_time;
|
|
||||||
rdtscl(start_time);
|
|
||||||
|
|
||||||
int loops = 0;
|
|
||||||
do {
|
|
||||||
loops++;
|
|
||||||
} while ((inb(0x61) & 0x20) == 0);
|
|
||||||
|
|
||||||
uint32_t end_time;
|
|
||||||
rdtscl(end_time);
|
|
||||||
|
|
||||||
uint32_t run_time = end_time - start_time;
|
|
||||||
|
|
||||||
// Make sure we have a credible result
|
|
||||||
if (loops >= 4 && run_time >= 50000) {
|
|
||||||
clks_per_msec = run_time / 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t memspeed(uintptr_t src, uint32_t len, int iter)
|
static uint32_t memspeed(uintptr_t src, uint32_t len, int iter)
|
||||||
{
|
{
|
||||||
uintptr_t dst;
|
uintptr_t dst;
|
||||||
|
@ -1083,12 +1052,14 @@ void cpuinfo_init(void)
|
||||||
determine_cache_size();
|
determine_cache_size();
|
||||||
|
|
||||||
determine_cpu_model();
|
determine_cpu_model();
|
||||||
|
|
||||||
measure_cpu_speed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void membw_init(void)
|
void membw_init(void)
|
||||||
{
|
{
|
||||||
|
if (quirk.type & QUIRK_TYPE_MEM_SIZE) {
|
||||||
|
quirk.process();
|
||||||
|
}
|
||||||
|
|
||||||
if(enable_bench) {
|
if(enable_bench) {
|
||||||
measure_memory_bandwidth();
|
measure_memory_bandwidth();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*//*
|
*//*
|
||||||
* Copyright (C) 2020-2022 Martin Whitaker.
|
* Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
* Copyright (C) 2004-2022 Sam Demeulemeester.
|
* Copyright (C) 2004-2023 Sam Demeulemeester.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#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_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_ICL 0x3040 // Core 10th Gen (IceLake-Y)
|
||||||
#define IMC_TGL 0x3050 // Core 11th Gen (Tiger Lake-U)
|
#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_BYT 0x4010 // Atom Bay Trail
|
||||||
#define IMC_CDT 0x4020 // Atom Cedar Trail
|
#define IMC_CDT 0x4020 // Atom Cedar Trail
|
||||||
|
@ -59,8 +60,9 @@
|
||||||
#define IMC_K16 0x8050 // Kabini & related (Family 16h)
|
#define IMC_K16 0x8050 // Kabini & related (Family 16h)
|
||||||
#define IMC_K17 0x8060 // Zen & Zen2 (Family 17h)
|
#define IMC_K17 0x8060 // Zen & Zen2 (Family 17h)
|
||||||
#define IMC_K18 0x8070 // Hygon (Family 18h)
|
#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_CZN 0x8081 // Cezanne APU
|
||||||
|
#define IMC_K19_RPL 0x8091 // Zen4 (Family 19h)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A string identifying the CPU make and model.
|
* A string identifying the CPU make and model.
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "heap.h"
|
||||||
#include "memrw32.h"
|
#include "memrw32.h"
|
||||||
#include "memsize.h"
|
#include "memsize.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include "pmem.h"
|
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
#define EHCI_USBCMD_ITC(n) ((n) << 16) // Interrupt Threshold Control = n (n = 1,2,4,8,16,32,64)
|
#define EHCI_USBCMD_ITC(n) ((n) << 16) // Interrupt Threshold Control = n (n = 1,2,4,8,16,32,64)
|
||||||
|
|
||||||
// USB Status register
|
// USB Status register
|
||||||
|
|
||||||
#define EHCI_USBSTS_INT 0x00000001 // Interrupt
|
#define EHCI_USBSTS_INT 0x00000001 // Interrupt
|
||||||
#define EHCI_USBSTS_ERR 0x00000002 // Error interrupt
|
#define EHCI_USBSTS_ERR 0x00000002 // Error interrupt
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
#define EHCI_USBSTS_PSS 0x00004000 // Periodic Schedule Status
|
#define EHCI_USBSTS_PSS 0x00004000 // Periodic Schedule Status
|
||||||
#define EHCI_USBSTS_ASS 0x00008000 // Asynchronous Schedule Status
|
#define EHCI_USBSTS_ASS 0x00008000 // Asynchronous Schedule Status
|
||||||
|
|
||||||
// Port Status and Control register
|
// Port Status and Control register
|
||||||
|
|
||||||
#define EHCI_PORT_SC_CCS 0x00000001 // Current Connect Status
|
#define EHCI_PORT_SC_CCS 0x00000001 // Current Connect Status
|
||||||
#define EHCI_PORT_SC_CCSC 0x00000002 // Current Connect Status Change
|
#define EHCI_PORT_SC_CCSC 0x00000002 // Current Connect Status Change
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
#define EHCI_PORT_SC_LS_J 0x00000800 // Line Status is J-state
|
#define EHCI_PORT_SC_LS_J 0x00000800 // Line Status is J-state
|
||||||
#define EHCI_PORT_SC_LS_U 0x00000c00 // Line Status is undefined
|
#define EHCI_PORT_SC_LS_U 0x00000c00 // Line Status is undefined
|
||||||
|
|
||||||
// Link Pointer
|
// Link Pointer
|
||||||
|
|
||||||
#define EHCI_LP_TERMINATE 0x00000001 // Terminate (T) bit
|
#define EHCI_LP_TERMINATE 0x00000001 // Terminate (T) bit
|
||||||
|
|
||||||
|
@ -226,11 +226,6 @@ typedef struct {
|
||||||
// Private Functions
|
// Private Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static size_t num_pages(size_t size)
|
|
||||||
{
|
|
||||||
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int usb_to_ehci_speed(usb_speed_t usb_speed)
|
static int usb_to_ehci_speed(usb_speed_t usb_speed)
|
||||||
{
|
{
|
||||||
switch (usb_speed) {
|
switch (usb_speed) {
|
||||||
|
@ -410,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)
|
usb_speed_t device_speed, int device_id, usb_ep_t *ep0)
|
||||||
{
|
{
|
||||||
// Store the extra information needed by build_ehci_qhd().
|
// Store the extra information needed by build_ehci_qhd().
|
||||||
ep0->driver_data = port_num << 8;
|
usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed);
|
||||||
if (hub->level > 0) {
|
ep0->driver_data = hs_parent.port_num << 8 | hs_parent.device_id;
|
||||||
ep0->driver_data |= hub->ep0->device_id;
|
|
||||||
}
|
|
||||||
if (!assign_usb_address(hcd, hub, port_num, device_speed, device_id, ep0)) {
|
if (!assign_usb_address(hcd, hub, port_num, device_speed, device_id, ep0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +486,7 @@ static const hcd_methods_t methods = {
|
||||||
// Public Functions
|
// 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;
|
ehci_cap_regs_t *cap_regs = (ehci_cap_regs_t *)base_addr;
|
||||||
|
|
||||||
|
@ -519,20 +513,35 @@ 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 (!halt_host_controller(op_regs)) return false;
|
||||||
if (!reset_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 = 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
|
// 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.
|
// don't support a programmable list length, so we just use the default length.
|
||||||
pm_map[0].end -= num_pages(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t));
|
uintptr_t pfl_addr = heap_alloc(HEAP_TYPE_LM_1, EHCI_MAX_PFL_LENGTH * sizeof(uint32_t), PAGE_SIZE);
|
||||||
uintptr_t pfl_addr = pm_map[0].end << PAGE_SHIFT;
|
if (pfl_addr == 0) {
|
||||||
|
goto no_keyboards_found;
|
||||||
|
}
|
||||||
uint32_t *pfl = (uint32_t *)pfl_addr;
|
uint32_t *pfl = (uint32_t *)pfl_addr;
|
||||||
|
|
||||||
for (int i = 0; i < EHCI_MAX_PFL_LENGTH; i++) {
|
for (int i = 0; i < EHCI_MAX_PFL_LENGTH; i++) {
|
||||||
pfl[i] = EHCI_LP_TERMINATE;
|
pfl[i] = EHCI_LP_TERMINATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory,
|
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||||
// so allocate it in the first segment.
|
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||||
// TODO: check for segment overflow.
|
if (workspace_addr == 0) {
|
||||||
pm_map[0].end -= num_pages(sizeof(workspace_t));
|
goto no_keyboards_found;
|
||||||
uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT;
|
}
|
||||||
workspace_t *ws = (workspace_t *)workspace_addr;
|
workspace_t *ws = (workspace_t *)workspace_addr;
|
||||||
|
|
||||||
memset(ws, 0, sizeof(workspace_t));
|
memset(ws, 0, sizeof(workspace_t));
|
||||||
|
@ -549,9 +558,7 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
write32(&op_regs->periodic_list_base, pfl_addr);
|
write32(&op_regs->periodic_list_base, pfl_addr);
|
||||||
write32(&op_regs->async_list_addr, (uintptr_t)(ws->qhd));
|
write32(&op_regs->async_list_addr, (uintptr_t)(ws->qhd));
|
||||||
if (!start_host_controller(op_regs)) {
|
if (!start_host_controller(op_regs)) {
|
||||||
pm_map[0].end += num_pages(sizeof(workspace_t));
|
goto no_keyboards_found;
|
||||||
pm_map[0].end += num_pages(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
flush32(&op_regs->config_flag, 1);
|
flush32(&op_regs->config_flag, 1);
|
||||||
|
|
||||||
|
@ -559,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.
|
// Construct a hub descriptor for the root hub.
|
||||||
usb_hub_t root_hub;
|
usb_hub_t root_hub;
|
||||||
|
memset(&root_hub, 0, sizeof(root_hub));
|
||||||
root_hub.ep0 = NULL;
|
root_hub.ep0 = NULL;
|
||||||
root_hub.level = 0;
|
|
||||||
root_hub.route = 0;
|
|
||||||
root_hub.num_ports = num_ehci_ports(hcs_params);
|
root_hub.num_ports = num_ehci_ports(hcs_params);
|
||||||
root_hub.power_up_delay = 10; // 20ms
|
root_hub.power_up_delay = 10; // 20ms
|
||||||
|
|
||||||
|
@ -647,17 +653,8 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_keyboards == 0) {
|
if (num_keyboards == 0) {
|
||||||
// Halt the host controller.
|
|
||||||
(void)halt_host_controller(op_regs);
|
(void)halt_host_controller(op_regs);
|
||||||
(void)reset_host_controller(op_regs);
|
goto no_keyboards_found;
|
||||||
|
|
||||||
// Deallocate the workspace for this controller.
|
|
||||||
pm_map[0].end += num_pages(sizeof(workspace_t));
|
|
||||||
|
|
||||||
// Deallocate the periodic frame list.
|
|
||||||
pm_map[0].end += num_pages(EHCI_MAX_PFL_LENGTH * sizeof(uint32_t));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ws->num_keyboards = num_keyboards;
|
ws->num_keyboards = num_keyboards;
|
||||||
|
@ -691,4 +688,8 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
enable_periodic_schedule(op_regs);
|
enable_periodic_schedule(op_regs);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
no_keyboards_found:
|
||||||
|
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,35 @@
|
||||||
#include "usbhcd.h"
|
#include "usbhcd.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the EHCI device identified by bus, dev, func, and base_addr,
|
* If necessary, takes ownership of the EHCI device at the specified base
|
||||||
* scans all the attached USB devices, and configures any HID USB keyboard
|
* address, then resets it.
|
||||||
* devices it finds to generate periodic interrupt transfers that report key
|
*
|
||||||
* presses. Initialises hcd and returns true if the device was successfully
|
* \param bus - the PCI bus number for accessing the device
|
||||||
* initialised and one or more keyboards were found.
|
* \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
|
#endif // EHCI_H
|
||||||
|
|
103
system/heap.c
Normal file
103
system/heap.c
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Copyright (C) 2022 Martin Whitaker.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot.h"
|
||||||
|
|
||||||
|
#include "memsize.h"
|
||||||
|
#include "pmem.h"
|
||||||
|
|
||||||
|
#include "heap.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int segment;
|
||||||
|
uintptr_t start;
|
||||||
|
uintptr_t end;
|
||||||
|
} heap_t;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Private Variables
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static heap_t heaps[HEAP_TYPE_LAST] = {
|
||||||
|
{ .segment = -1, .start = 0, .end = 0 },
|
||||||
|
{ .segment = -1, .start = 0, .end = 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Private Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static size_t num_pages(size_t size)
|
||||||
|
{
|
||||||
|
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
uintptr_t addr = pm_map[heap->segment].end - num_pages(size);
|
||||||
|
addr &= ~((alignment - 1) >> PAGE_SHIFT);
|
||||||
|
if (addr < heap->start) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pm_map[heap->segment].end = addr;
|
||||||
|
return addr << PAGE_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Public Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void heap_init(void)
|
||||||
|
{
|
||||||
|
// Use the largest 20-bit addressable physical memory segment for the low-memory heap.
|
||||||
|
// Use the largest 32-bit addressable physical memory segment for the high-memory heap.
|
||||||
|
// Exclude memory occupied by the program or below it in that segment.
|
||||||
|
uintptr_t program_start = (uintptr_t)_start >> PAGE_SHIFT;
|
||||||
|
uintptr_t program_end = program_start + num_pages(_end - _start);
|
||||||
|
uintptr_t max_segment_size = 0;
|
||||||
|
for (int i = 0; i < pm_map_size && pm_map[i].end <= PAGE_C(4,GB); i++) {
|
||||||
|
uintptr_t try_heap_start = pm_map[i].start;
|
||||||
|
uintptr_t try_heap_end = pm_map[i].end;
|
||||||
|
if (program_start >= try_heap_start && program_end <= try_heap_end) {
|
||||||
|
try_heap_start = program_end;
|
||||||
|
}
|
||||||
|
uintptr_t segment_size = try_heap_end - try_heap_start;
|
||||||
|
if (segment_size >= max_segment_size) {
|
||||||
|
max_segment_size = segment_size;
|
||||||
|
if (try_heap_end <= PAGE_C(1,MB)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
system/heap.h
Normal file
65
system/heap.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#ifndef HEAP_H
|
||||||
|
#define HEAP_H
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* Provides functions to allocate and free chunks of physical memory that will
|
||||||
|
* be excluded from the memory tests. Two separate heaps are supported, one in
|
||||||
|
* low (20-bit addressable) memory, the other in high (32-bit addressable)
|
||||||
|
* memory.
|
||||||
|
*
|
||||||
|
*//*
|
||||||
|
* Copyright (C) 2022 Martin Whitaker.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 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 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 heap_alloc(heap_type_t heap_id, size_t size, uintptr_t alignment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 heap_mark(heap_type_t heap_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees any memory allocated in the given heap since the specified mark was
|
||||||
|
* obtained from a call to heap_mark().
|
||||||
|
*
|
||||||
|
* \param heap_id - the target heap.
|
||||||
|
* \param mark - the mark that indicates how much memory to free.
|
||||||
|
*/
|
||||||
|
void heap_rewind(heap_type_t heap_id, uintptr_t mark);
|
||||||
|
|
||||||
|
#endif // HEAP_H
|
|
@ -1,5 +1,5 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// 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
|
// This file is used to detect quirks on specific hardware
|
||||||
|
@ -12,6 +12,10 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
|
#include "cpuinfo.h"
|
||||||
|
#include "cpuid.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "temperature.h"
|
||||||
|
|
||||||
quirk_t quirk;
|
quirk_t quirk;
|
||||||
|
|
||||||
|
@ -44,6 +48,57 @@ static void asus_tusl2_configure_mux(void)
|
||||||
outb(0xAA, 0x2E);
|
outb(0xAA, 0x2E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_m1541_l2_cache_size(void)
|
||||||
|
{
|
||||||
|
if (l2_cache != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if L2 cache is enabled with L2CC-2 Register[0]
|
||||||
|
if ((pci_config_read8(0, 0, 0, 0x42) & 1) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get L2 Cache Size with L2CC-1 Register[3:2]
|
||||||
|
uint8_t reg = (pci_config_read8(0, 0, 0, 0x41) >> 2) & 3;
|
||||||
|
|
||||||
|
if (reg == 0b00) { l2_cache = 256; }
|
||||||
|
if (reg == 0b01) { l2_cache = 512; }
|
||||||
|
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 --
|
// -- Public function --
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
@ -52,8 +107,20 @@ void quirks_init(void)
|
||||||
{
|
{
|
||||||
quirk.id = QUIRK_NONE;
|
quirk.id = QUIRK_NONE;
|
||||||
quirk.type = QUIRK_TYPE_NONE;
|
quirk.type = QUIRK_TYPE_NONE;
|
||||||
quirk.root_vid = pci_config_read16(0, 0, 0, 0);
|
quirk.root_vid = pci_config_read16(0, 0, 0, PCI_VID_REG);
|
||||||
quirk.root_did = pci_config_read16(0, 0, 0, 2);
|
quirk.root_did = pci_config_read16(0, 0, 0, PCI_DID_REG);
|
||||||
|
quirk.process = NULL;
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// -- ALi Aladdin V Quirk --
|
||||||
|
// -------------------------
|
||||||
|
// 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 == 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;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// -- ASUS TUSL2-C Quirk --
|
// -- ASUS TUSL2-C Quirk --
|
||||||
|
@ -61,12 +128,74 @@ void quirks_init(void)
|
||||||
// This motherboard has an ASB100 ASIC with a SMBUS Mux Integrated.
|
// This motherboard has an ASB100 ASIC with a SMBUS Mux Integrated.
|
||||||
// To access SPD later in the code, we need to configure the mux.
|
// To access SPD later in the code, we need to configure the mux.
|
||||||
// PS: Detection via DMI is unreliable, so using Root PCI Registers
|
// PS: Detection via DMI is unreliable, so using Root PCI Registers
|
||||||
if (quirk.root_vid == 0x8086 && quirk.root_did == 0x1130) { // Intel i815
|
if (quirk.root_vid == PCI_VID_INTEL && quirk.root_did == 0x1130) { // Intel i815
|
||||||
if (pci_config_read16(0, 0, 0, 0x2C) == 0x1043) { // ASUS
|
if (pci_config_read16(0, 0, 0, PCI_SUB_VID_REG) == PCI_VID_ASUS) { // ASUS
|
||||||
if (pci_config_read16(0, 0, 0, 0x2E) == 0x8027) { // TUSL2-C
|
if (pci_config_read16(0, 0, 0, PCI_SUB_DID_REG) == 0x8027) { // TUSL2-C
|
||||||
quirk.id = QUIRK_TUSL2;
|
quirk.id = QUIRK_TUSL2;
|
||||||
quirk.type |= QUIRK_TYPE_SMBUS;
|
quirk.type |= QUIRK_TYPE_SMBUS;
|
||||||
asus_tusl2_configure_mux();
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,25 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#define QUIRK_TYPE_NONE 0b00000000
|
#define QUIRK_TYPE_NONE (1 << 0)
|
||||||
#define QUIRK_TYPE_USB 0b00000001
|
#define QUIRK_TYPE_USB (1 << 1)
|
||||||
#define QUIRK_TYPE_SMP 0b00000010
|
#define QUIRK_TYPE_SMP (1 << 2)
|
||||||
#define QUIRK_TYPE_SMBIOS 0b00000100
|
#define QUIRK_TYPE_SMBIOS (1 << 3)
|
||||||
#define QUIRK_TYPE_SMBUS 0b00001000
|
#define QUIRK_TYPE_SMBUS (1 << 4)
|
||||||
#define QUIRK_TYPE_TIMER 0b00010000
|
#define QUIRK_TYPE_TIMER (1 << 5)
|
||||||
|
#define QUIRK_TYPE_MEM_SIZE (1 << 6)
|
||||||
|
#define QUIRK_TYPE_TEMP (1 << 7)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QUIRK_NONE,
|
QUIRK_NONE,
|
||||||
QUIRK_TUSL2
|
QUIRK_TUSL2,
|
||||||
|
QUIRK_ALI_ALADDIN_V,
|
||||||
|
QUIRK_X10SDV_NOSMP,
|
||||||
|
QUIRK_K8_BSTEP_NOTEMP,
|
||||||
|
QUIRK_K8_REVFG_TEMP,
|
||||||
|
QUIRK_AMD_ERRATA_319
|
||||||
} quirk_id_t;
|
} quirk_id_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -28,6 +36,7 @@ typedef struct {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint16_t root_vid;
|
uint16_t root_vid;
|
||||||
uint16_t root_did;
|
uint16_t root_did;
|
||||||
|
void (*process)(void);
|
||||||
} quirk_t;
|
} quirk_t;
|
||||||
|
|
||||||
extern quirk_t quirk;
|
extern quirk_t quirk;
|
||||||
|
|
|
@ -79,7 +79,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x003D, "Tektronix" },
|
// { 0x003D, "Tektronix" },
|
||||||
// { 0x003E, "Oracle Corporation" },
|
// { 0x003E, "Oracle Corporation" },
|
||||||
// { 0x003F, "Silicon Storage Technology" },
|
// { 0x003F, "Silicon Storage Technology" },
|
||||||
// { 0x0040, "ProMos/Mosel Vitelic" },
|
{ 0x0040, "MOSEL" },
|
||||||
{ 0x0041, "Infineon" },
|
{ 0x0041, "Infineon" },
|
||||||
{ 0x0042, "Macronix" },
|
{ 0x0042, "Macronix" },
|
||||||
// { 0x0043, "Xerox" },
|
// { 0x0043, "Xerox" },
|
||||||
|
@ -161,7 +161,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0111, "DATARAM" },
|
// { 0x0111, "DATARAM" },
|
||||||
// { 0x0112, "United Microelectronics Corp" },
|
// { 0x0112, "United Microelectronics Corp" },
|
||||||
// { 0x0113, "TCSI" },
|
// { 0x0113, "TCSI" },
|
||||||
// { 0x0114, "Smart Modular" },
|
{ 0x0114, "Smart Modular" },
|
||||||
// { 0x0115, "Hughes Aircraft" },
|
// { 0x0115, "Hughes Aircraft" },
|
||||||
// { 0x0116, "Lanstar Semiconductor" },
|
// { 0x0116, "Lanstar Semiconductor" },
|
||||||
// { 0x0117, "Qlogic" },
|
// { 0x0117, "Qlogic" },
|
||||||
|
@ -392,7 +392,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x027B, "Accelerant Networks" },
|
// { 0x027B, "Accelerant Networks" },
|
||||||
// { 0x027C, "Silicon Wave" },
|
// { 0x027C, "Silicon Wave" },
|
||||||
// { 0x027D, "SandCraft" },
|
// { 0x027D, "SandCraft" },
|
||||||
// { 0x027E, "Elpida" },
|
{ 0x027E, "Elpida" },
|
||||||
// { 0x0301, "Solectron" },
|
// { 0x0301, "Solectron" },
|
||||||
// { 0x0302, "Optosys Technologies" },
|
// { 0x0302, "Optosys Technologies" },
|
||||||
// { 0x0303, "Buffalo (Formerly Melco)" },
|
// { 0x0303, "Buffalo (Formerly Melco)" },
|
||||||
|
@ -407,14 +407,14 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x030C, "Elite Flash Storage" },
|
// { 0x030C, "Elite Flash Storage" },
|
||||||
// { 0x030D, "Mysticom" },
|
// { 0x030D, "Mysticom" },
|
||||||
// { 0x030E, "LightSand Communications" },
|
// { 0x030E, "LightSand Communications" },
|
||||||
// { 0x030F, "ATI Technologies" },
|
{ 0x030F, "ATI" },
|
||||||
// { 0x0310, "Agere Systems" },
|
// { 0x0310, "Agere Systems" },
|
||||||
// { 0x0311, "NeoMagic" },
|
// { 0x0311, "NeoMagic" },
|
||||||
// { 0x0312, "AuroraNetics" },
|
// { 0x0312, "AuroraNetics" },
|
||||||
// { 0x0313, "Golden Empire" },
|
{ 0x0313, "GEIL" },
|
||||||
{ 0x0314, "Mushkin" },
|
{ 0x0314, "Mushkin" },
|
||||||
// { 0x0315, "Tioga Technologies" },
|
// { 0x0315, "Tioga Technologies" },
|
||||||
// { 0x0316, "Netlist" },
|
{ 0x0316, "Netlist" },
|
||||||
// { 0x0317, "TeraLogic" },
|
// { 0x0317, "TeraLogic" },
|
||||||
// { 0x0318, "Cicada Semiconductor" },
|
// { 0x0318, "Cicada Semiconductor" },
|
||||||
// { 0x0319, "Centon Electronics" },
|
// { 0x0319, "Centon Electronics" },
|
||||||
|
@ -478,9 +478,9 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0353, "Primarion" },
|
// { 0x0353, "Primarion" },
|
||||||
// { 0x0354, "Picochip Designs Ltd" },
|
// { 0x0354, "Picochip Designs Ltd" },
|
||||||
// { 0x0355, "Silverback Systems" },
|
// { 0x0355, "Silverback Systems" },
|
||||||
// { 0x0356, "Jade Star Technologies" },
|
{ 0x0356, "Jade Star" },
|
||||||
// { 0x0357, "Pijnenburg Securealink" },
|
// { 0x0357, "Pijnenburg Securealink" },
|
||||||
// { 0x0358, "takeMS - Ultron AG" },
|
{ 0x0358, "takeMS" }, // Ultron AG
|
||||||
// { 0x0359, "Cambridge Silicon Radio" },
|
// { 0x0359, "Cambridge Silicon Radio" },
|
||||||
{ 0x035A, "Swissbit" },
|
{ 0x035A, "Swissbit" },
|
||||||
// { 0x035B, "Nazomi Communications" },
|
// { 0x035B, "Nazomi Communications" },
|
||||||
|
@ -540,7 +540,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0413, "Digital Communications Technology Inc" },
|
// { 0x0413, "Digital Communications Technology Inc" },
|
||||||
// { 0x0414, "Silicon-Based Technology" },
|
// { 0x0414, "Silicon-Based Technology" },
|
||||||
// { 0x0415, "Fulcrum Microsystems" },
|
// { 0x0415, "Fulcrum Microsystems" },
|
||||||
// { 0x0416, "Positivo Informatica Ltd" },
|
{ 0x0416, "Positivo" },
|
||||||
// { 0x0417, "XIOtech Corporation" },
|
// { 0x0417, "XIOtech Corporation" },
|
||||||
// { 0x0418, "PortalPlayer" },
|
// { 0x0418, "PortalPlayer" },
|
||||||
// { 0x0419, "Zhiying Software" },
|
// { 0x0419, "Zhiying Software" },
|
||||||
|
@ -585,7 +585,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0440, "Bandspeed" },
|
// { 0x0440, "Bandspeed" },
|
||||||
// { 0x0441, "LeWiz Communications" },
|
// { 0x0441, "LeWiz Communications" },
|
||||||
// { 0x0442, "CPU Technology" },
|
// { 0x0442, "CPU Technology" },
|
||||||
// { 0x0443, "Ramaxel Technology" },
|
{ 0x0443, "Ramaxel" },
|
||||||
// { 0x0444, "DSP Group" },
|
// { 0x0444, "DSP Group" },
|
||||||
// { 0x0445, "Axis Communications" },
|
// { 0x0445, "Axis Communications" },
|
||||||
// { 0x0446, "Legacy Electronics" },
|
// { 0x0446, "Legacy Electronics" },
|
||||||
|
@ -706,7 +706,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x053B, "Solid State System Co Ltd" },
|
// { 0x053B, "Solid State System Co Ltd" },
|
||||||
// { 0x053C, "Kian Tech LLC" },
|
// { 0x053C, "Kian Tech LLC" },
|
||||||
// { 0x053D, "Artimi" },
|
// { 0x053D, "Artimi" },
|
||||||
// { 0x053E, "Power Quotient International" },
|
{ 0x053E, "PQI" },
|
||||||
// { 0x053F, "Avago Technologies" },
|
// { 0x053F, "Avago Technologies" },
|
||||||
// { 0x0540, "ADTechnology" },
|
// { 0x0540, "ADTechnology" },
|
||||||
// { 0x0541, "Sigma Designs" },
|
// { 0x0541, "Sigma Designs" },
|
||||||
|
@ -730,20 +730,20 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0553, "Velogix" },
|
// { 0x0553, "Velogix" },
|
||||||
// { 0x0554, "Montalvo Systems" },
|
// { 0x0554, "Montalvo Systems" },
|
||||||
// { 0x0555, "iVivity Inc" },
|
// { 0x0555, "iVivity Inc" },
|
||||||
// { 0x0556, "Walton Chaintech" },
|
{ 0x0556, "Walton Chaintech" },
|
||||||
// { 0x0557, "AENEON" },
|
{ 0x0557, "AENEON" },
|
||||||
// { 0x0558, "Lorom Industrial Co Ltd" },
|
// { 0x0558, "Lorom Industrial Co Ltd" },
|
||||||
// { 0x0559, "Radiospire Networks" },
|
// { 0x0559, "Radiospire Networks" },
|
||||||
// { 0x055A, "Sensio Technologies Inc" },
|
// { 0x055A, "Sensio Technologies Inc" },
|
||||||
// { 0x055B, "Nethra Imaging" },
|
// { 0x055B, "Nethra Imaging" },
|
||||||
// { 0x055C, "Hexon Technology Pte Ltd" },
|
{ 0x055C, "Hexon" },
|
||||||
// { 0x055D, "CompuStocx (CSX)" },
|
// { 0x055D, "CompuStocx (CSX)" },
|
||||||
// { 0x055E, "Methode Electronics Inc" },
|
// { 0x055E, "Methode Electronics Inc" },
|
||||||
// { 0x055F, "Connect One Ltd" },
|
// { 0x055F, "Connect One Ltd" },
|
||||||
// { 0x0560, "Opulan Technologies" },
|
// { 0x0560, "Opulan Technologies" },
|
||||||
// { 0x0561, "Septentrio NV" },
|
// { 0x0561, "Septentrio NV" },
|
||||||
// { 0x0562, "Goldenmars Technology Inc" },
|
{ 0x0562, "Goldenmars" },
|
||||||
// { 0x0563, "Kreton Corporation" },
|
{ 0x0563, "Kreton Corp." },
|
||||||
// { 0x0564, "Cochlear Ltd" },
|
// { 0x0564, "Cochlear Ltd" },
|
||||||
// { 0x0565, "Altair Semiconductor" },
|
// { 0x0565, "Altair Semiconductor" },
|
||||||
// { 0x0566, "NetEffect Inc" },
|
// { 0x0566, "NetEffect Inc" },
|
||||||
|
@ -835,7 +835,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x063E, "Wilocity" },
|
// { 0x063E, "Wilocity" },
|
||||||
// { 0x063F, "Novafora Inc" },
|
// { 0x063F, "Novafora Inc" },
|
||||||
// { 0x0640, "iKoa Corporation" },
|
// { 0x0640, "iKoa Corporation" },
|
||||||
// { 0x0641, "ASint Technology" },
|
{ 0x0641, "ASint" },
|
||||||
{ 0x0642, "Ramtron" },
|
{ 0x0642, "Ramtron" },
|
||||||
// { 0x0643, "Plato Networks Inc" },
|
// { 0x0643, "Plato Networks Inc" },
|
||||||
// { 0x0644, "IPtronics AS" },
|
// { 0x0644, "IPtronics AS" },
|
||||||
|
@ -874,7 +874,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0666, "Netronome" },
|
// { 0x0666, "Netronome" },
|
||||||
// { 0x0667, "Zenverge Inc" },
|
// { 0x0667, "Zenverge Inc" },
|
||||||
// { 0x0668, "N-trig Ltd" },
|
// { 0x0668, "N-trig Ltd" },
|
||||||
// { 0x0669, "SanMax Technologies Inc" },
|
{ 0x0669, "SanMax" },
|
||||||
// { 0x066A, "Contour Semiconductor Inc" },
|
// { 0x066A, "Contour Semiconductor Inc" },
|
||||||
{ 0x066B, "TwinMOS" },
|
{ 0x066B, "TwinMOS" },
|
||||||
// { 0x066C, "Silicon Systems Inc" },
|
// { 0x066C, "Silicon Systems Inc" },
|
||||||
|
@ -882,7 +882,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x066E, "Certicom Corporation" },
|
// { 0x066E, "Certicom Corporation" },
|
||||||
// { 0x066F, "JSC ICC Milandr" },
|
// { 0x066F, "JSC ICC Milandr" },
|
||||||
// { 0x0670, "PhotoFast Global Inc" },
|
// { 0x0670, "PhotoFast Global Inc" },
|
||||||
// { 0x0671, "InnoDisk Corporation" },
|
{ 0x0671, "InnoDisk" },
|
||||||
// { 0x0672, "Muscle Power" },
|
// { 0x0672, "Muscle Power" },
|
||||||
// { 0x0673, "Energy Micro" },
|
// { 0x0673, "Energy Micro" },
|
||||||
// { 0x0674, "Innofidei" },
|
// { 0x0674, "Innofidei" },
|
||||||
|
@ -987,7 +987,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x075A, "Bestdon Technology Co Ltd" },
|
// { 0x075A, "Bestdon Technology Co Ltd" },
|
||||||
// { 0x075B, "Baysand Inc" },
|
// { 0x075B, "Baysand Inc" },
|
||||||
// { 0x075C, "Uroad Technology Co Ltd" },
|
// { 0x075C, "Uroad Technology Co Ltd" },
|
||||||
// { 0x075D, "Wilk Elektronik S.A." },
|
{ 0x075D, "Wilk Elektronik" },
|
||||||
// { 0x075E, "AAI" },
|
// { 0x075E, "AAI" },
|
||||||
// { 0x075F, "Harman" },
|
// { 0x075F, "Harman" },
|
||||||
// { 0x0760, "Berg Microelectronics Inc" },
|
// { 0x0760, "Berg Microelectronics Inc" },
|
||||||
|
@ -1038,12 +1038,12 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0810, "Exelis" },
|
// { 0x0810, "Exelis" },
|
||||||
// { 0x0811, "Satixfy Ltd" },
|
// { 0x0811, "Satixfy Ltd" },
|
||||||
// { 0x0812, "Galaxy Microsystems Ltd" },
|
// { 0x0812, "Galaxy Microsystems Ltd" },
|
||||||
// { 0x0813, "Gloway International Co Ltd" },
|
{ 0x0813, "Gloway" },
|
||||||
// { 0x0814, "Lab" },
|
// { 0x0814, "Lab" },
|
||||||
// { 0x0815, "Smart Energy Instruments" },
|
// { 0x0815, "Smart Energy Instruments" },
|
||||||
// { 0x0816, "Approved Memory Corporation" },
|
// { 0x0816, "Approved Memory Corporation" },
|
||||||
// { 0x0817, "Axell Corporation" },
|
// { 0x0817, "Axell Corporation" },
|
||||||
// { 0x0818, "Essencore Limited" },
|
{ 0x0818, "KLEVV" },
|
||||||
// { 0x0819, "Phytium" },
|
// { 0x0819, "Phytium" },
|
||||||
// { 0x081A, "Xi'an UniIC Semiconductors Co Ltd" },
|
// { 0x081A, "Xi'an UniIC Semiconductors Co Ltd" },
|
||||||
// { 0x081B, "Ambiq Micro" },
|
// { 0x081B, "Ambiq Micro" },
|
||||||
|
@ -1098,7 +1098,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x084C, "Shenzhen Pango Microsystems Co Ltd" },
|
// { 0x084C, "Shenzhen Pango Microsystems Co Ltd" },
|
||||||
// { 0x084D, "Vasekey" },
|
// { 0x084D, "Vasekey" },
|
||||||
// { 0x084F, "Eyenix Co Ltd" },
|
// { 0x084F, "Eyenix Co Ltd" },
|
||||||
// { 0x0850, "Heoriady" },
|
{ 0x0850, "Heoriady" },
|
||||||
// { 0x0851, "Accelerated Memory Production Inc" },
|
// { 0x0851, "Accelerated Memory Production Inc" },
|
||||||
// { 0x0852, "INVECAS Inc" },
|
// { 0x0852, "INVECAS Inc" },
|
||||||
// { 0x0853, "AP Memory" },
|
// { 0x0853, "AP Memory" },
|
||||||
|
@ -1208,7 +1208,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x093F, "Pegasus Semiconductor (Shanghai) Co" },
|
// { 0x093F, "Pegasus Semiconductor (Shanghai) Co" },
|
||||||
// { 0x0940, "Mythic Inc" },
|
// { 0x0940, "Mythic Inc" },
|
||||||
// { 0x0941, "Elmos Semiconductor AG" },
|
// { 0x0941, "Elmos Semiconductor AG" },
|
||||||
// { 0x0942, "Kllisre" },
|
{ 0x0942, "Kllisre" },
|
||||||
// { 0x0943, "Shenzhen Winconway Technology" },
|
// { 0x0943, "Shenzhen Winconway Technology" },
|
||||||
// { 0x0944, "Shenzhen Xingmem Technology Corp" },
|
// { 0x0944, "Shenzhen Xingmem Technology Corp" },
|
||||||
// { 0x0945, "Gold Key Technology Co Ltd" },
|
// { 0x0945, "Gold Key Technology Co Ltd" },
|
||||||
|
@ -1261,7 +1261,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0974, "Hyundai Inc" },
|
// { 0x0974, "Hyundai Inc" },
|
||||||
// { 0x0975, "EXCELERAM" },
|
// { 0x0975, "EXCELERAM" },
|
||||||
// { 0x0976, "PsiKick" },
|
// { 0x0976, "PsiKick" },
|
||||||
// { 0x0977, "Netac Technology Co Ltd" },
|
{ 0x0977, "Netac" },
|
||||||
{ 0x0978, "PCCOOLER" },
|
{ 0x0978, "PCCOOLER" },
|
||||||
// { 0x0979, "Jiangsu Huacun Electronic Technology" },
|
// { 0x0979, "Jiangsu Huacun Electronic Technology" },
|
||||||
// { 0x097A, "Shenzhen Micro Innovation Industry" },
|
// { 0x097A, "Shenzhen Micro Innovation Industry" },
|
||||||
|
@ -1335,7 +1335,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0A42, "Thermaltake Technology Co Ltd" },
|
// { 0x0A42, "Thermaltake Technology Co Ltd" },
|
||||||
// { 0x0A43, "Shenzhen O?Yang Maile Technology Ltd" },
|
// { 0x0A43, "Shenzhen O?Yang Maile Technology Ltd" },
|
||||||
// { 0x0A44, "UPMEM" },
|
// { 0x0A44, "UPMEM" },
|
||||||
// { 0x0A45, "Chun Well Technology Holding Limited" },
|
{ 0x0A45, "Chun Well" },
|
||||||
// { 0x0A46, "Astera Labs Inc" },
|
// { 0x0A46, "Astera Labs Inc" },
|
||||||
// { 0x0A47, "Winconway" },
|
// { 0x0A47, "Winconway" },
|
||||||
// { 0x0A48, "Advantech Co Ltd" },
|
// { 0x0A48, "Advantech Co Ltd" },
|
||||||
|
@ -1384,7 +1384,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0A73, "MCLogic Inc" },
|
// { 0x0A73, "MCLogic Inc" },
|
||||||
// { 0x0A74, "Eorex Corporation" },
|
// { 0x0A74, "Eorex Corporation" },
|
||||||
// { 0x0A75, "Arm Technology (China) Co Ltd" },
|
// { 0x0A75, "Arm Technology (China) Co Ltd" },
|
||||||
// { 0x0A76, "Lexar Co Limited" },
|
{ 0x0A76, "Lexar" },
|
||||||
// { 0x0A77, "QinetiQ Group plc" },
|
// { 0x0A77, "QinetiQ Group plc" },
|
||||||
// { 0x0A78, "Exascend" },
|
// { 0x0A78, "Exascend" },
|
||||||
// { 0x0A79, "Hong Kong Hyunion Electronics Co Ltd" },
|
// { 0x0A79, "Hong Kong Hyunion Electronics Co Ltd" },
|
||||||
|
@ -1410,7 +1410,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0B0F, "Quadratica LLC" },
|
// { 0x0B0F, "Quadratica LLC" },
|
||||||
// { 0x0B10, "Anpec Electronics" },
|
// { 0x0B10, "Anpec Electronics" },
|
||||||
// { 0x0B11, "Xi'an Morebeck Semiconductor Tech Co" },
|
// { 0x0B11, "Xi'an Morebeck Semiconductor Tech Co" },
|
||||||
// { 0x0B12, "Kingbank Technology Co Ltd" },
|
{ 0x0B12, "Kingbank" },
|
||||||
// { 0x0B13, "ITRenew Inc" },
|
// { 0x0B13, "ITRenew Inc" },
|
||||||
// { 0x0B14, "Shenzhen Eaget Innovation Tech Ltd" },
|
// { 0x0B14, "Shenzhen Eaget Innovation Tech Ltd" },
|
||||||
// { 0x0B15, "Jazer" },
|
// { 0x0B15, "Jazer" },
|
||||||
|
@ -1556,7 +1556,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0C23, "Tangem AG" },
|
// { 0x0C23, "Tangem AG" },
|
||||||
// { 0x0C24, "FuturePath Technology (Shenzhen) Co" },
|
// { 0x0C24, "FuturePath Technology (Shenzhen) Co" },
|
||||||
// { 0x0C25, "RC Module" },
|
// { 0x0C25, "RC Module" },
|
||||||
// { 0x0C26, "Timetec International Inc" },
|
{ 0x0C26, "Timetec" },
|
||||||
// { 0x0C27, "ICMAX Technologies Co Limited" },
|
// { 0x0C27, "ICMAX Technologies Co Limited" },
|
||||||
// { 0x0C28, "Lynxi Technologies Ltd Co" },
|
// { 0x0C28, "Lynxi Technologies Ltd Co" },
|
||||||
// { 0x0C29, "Guangzhou Taisupanke Computer Equipment" },
|
// { 0x0C29, "Guangzhou Taisupanke Computer Equipment" },
|
||||||
|
@ -1611,7 +1611,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
|
||||||
// { 0x0C5A, "Fraunhofer IPMS" },
|
// { 0x0C5A, "Fraunhofer IPMS" },
|
||||||
// { 0x0C5B, "Shenzhen Daxinlang Electronic Tech Co" },
|
// { 0x0C5B, "Shenzhen Daxinlang Electronic Tech Co" },
|
||||||
// { 0x0C5C, "Abacus Peripherals Private Limited" },
|
// { 0x0C5C, "Abacus Peripherals Private Limited" },
|
||||||
// { 0x0C5D, "OLOy Technology" },
|
{ 0x0C5D, "OLOy" },
|
||||||
// { 0x0C5E, "Wuhan P&S Semiconductor Co Ltd" },
|
// { 0x0C5E, "Wuhan P&S Semiconductor Co Ltd" },
|
||||||
// { 0x0C5F, "Sitrus Technology" },
|
// { 0x0C5F, "Sitrus Technology" },
|
||||||
// { 0x0C60, "AnHui Conner Storage Co Ltd" },
|
// { 0x0C60, "AnHui Conner Storage Co Ltd" },
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bootparams.h"
|
||||||
|
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "usbhcd.h"
|
#include "usbhcd.h"
|
||||||
|
|
||||||
|
@ -212,7 +214,7 @@ static const char usb_hid_keymap[] = {
|
||||||
// Public Variables
|
// Public Variables
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
keyboard_types_t keyboard_types = KT_LEGACY | KT_USB;
|
keyboard_types_t keyboard_types = KT_NONE;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Public Functions
|
// Public Functions
|
||||||
|
@ -220,6 +222,16 @@ keyboard_types_t keyboard_types = KT_LEGACY | KT_USB;
|
||||||
|
|
||||||
void keyboard_init(void)
|
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) {
|
if (keyboard_types & KT_USB) {
|
||||||
find_usb_keyboards(keyboard_types == KT_USB);
|
find_usb_keyboards(keyboard_types == KT_USB);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
#define MSR_AMD64_NB_CFG 0xc001001f
|
#define MSR_AMD64_NB_CFG 0xc001001f
|
||||||
#define MSR_AMD64_COFVID_STATUS 0xc0010071
|
#define MSR_AMD64_COFVID_STATUS 0xc0010071
|
||||||
|
|
||||||
|
#define MSR_VIA_TEMP_C7 0x1169
|
||||||
|
#define MSR_VIA_TEMP_NANO 0x1423
|
||||||
|
|
||||||
#define rdmsr(msr, value1, value2) \
|
#define rdmsr(msr, value1, value2) \
|
||||||
__asm__ __volatile__("rdmsr" \
|
__asm__ __volatile__("rdmsr" \
|
||||||
: "=a" (value1), \
|
: "=a" (value1), \
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "heap.h"
|
||||||
#include "memrw32.h"
|
#include "memrw32.h"
|
||||||
#include "memsize.h"
|
#include "memsize.h"
|
||||||
#include "pmem.h"
|
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
@ -243,9 +243,34 @@ typedef struct {
|
||||||
// Private Functions
|
// Private Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static size_t num_pages(size_t size)
|
static bool reset_host_controller(ohci_op_regs_t *op_regs)
|
||||||
{
|
{
|
||||||
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
// 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)
|
static bool reset_ohci_port(ohci_op_regs_t *op_regs, int port_idx)
|
||||||
|
@ -411,11 +436,11 @@ static const hcd_methods_t methods = {
|
||||||
// Public Functions
|
// 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;
|
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) {
|
if ((read32(&op_regs->revision) & 0xff) != 0x10) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -429,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.
|
// Preserve the frame interval set by the SMM or BIOS.
|
||||||
// If not set, use the default value.
|
// If not set, use the default value.
|
||||||
uint32_t frame_interval = read32(&op_regs->fm_interval) & 0x3fff;
|
uint32_t frame_interval = read32(&op_regs->fm_interval) & 0x3fff;
|
||||||
|
@ -436,36 +475,21 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
frame_interval = 0x2edf;
|
frame_interval = 0x2edf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for host controller setup (see section 5.1.1.3 of the OHCI spec.).
|
// We will have already reset the controller, but can't guarantee to get
|
||||||
switch (read32(&op_regs->control) & OHCI_CTRL_HCFS) {
|
// here within the 2ms time limit for moving directly from suspend state
|
||||||
case OHCI_CTRL_HCFS_RST:
|
// to operational state. So reset it again.
|
||||||
usleep(50*MILLISEC);
|
if (!reset_host_controller(op_regs)) {
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check we are now in SUSPEND state.
|
// Record the heap state to allow us to free memory.
|
||||||
if ((read32(&op_regs->control) & OHCI_CTRL_HCFS) != OHCI_CTRL_HCFS_SUS) {
|
uintptr_t initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory,
|
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||||
// so allocate it in the first segment.
|
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||||
// TODO: check for segment overflow.
|
if (workspace_addr == 0) {
|
||||||
pm_map[0].end -= num_pages(sizeof(workspace_t));
|
goto no_keyboards_found;
|
||||||
uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT;
|
}
|
||||||
workspace_t *ws = (workspace_t *)workspace_addr;
|
workspace_t *ws = (workspace_t *)workspace_addr;
|
||||||
|
|
||||||
memset(ws, 0, sizeof(workspace_t));
|
memset(ws, 0, sizeof(workspace_t));
|
||||||
|
@ -500,9 +524,8 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
|
|
||||||
// Construct a hub descriptor for the root hub.
|
// Construct a hub descriptor for the root hub.
|
||||||
usb_hub_t root_hub;
|
usb_hub_t root_hub;
|
||||||
|
memset(&root_hub, 0, sizeof(root_hub));
|
||||||
root_hub.ep0 = NULL;
|
root_hub.ep0 = NULL;
|
||||||
root_hub.level = 0;
|
|
||||||
root_hub.route = 0;
|
|
||||||
root_hub.num_ports = rh_descriptor_a & 0xf;
|
root_hub.num_ports = rh_descriptor_a & 0xf;
|
||||||
root_hub.power_up_delay = rh_descriptor_a >> 24;
|
root_hub.power_up_delay = rh_descriptor_a >> 24;
|
||||||
|
|
||||||
|
@ -574,10 +597,7 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
// Delay to allow the controller to reset.
|
// Delay to allow the controller to reset.
|
||||||
usleep(10);
|
usleep(10);
|
||||||
|
|
||||||
// Deallocate the workspace for this controller.
|
goto no_keyboards_found;
|
||||||
pm_map[0].end += num_pages(sizeof(workspace_t));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -611,4 +631,8 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
flush32(&op_regs->interrupt_status, ~0);
|
flush32(&op_regs->interrupt_status, ~0);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
no_keyboards_found:
|
||||||
|
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,32 @@
|
||||||
#include "usbhcd.h"
|
#include "usbhcd.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the OHCI device found at base_addr, scans all the attached USB
|
* If necessary, takes ownership of the OHCI device at the specified base
|
||||||
* devices, and configures any HID USB keyboard devices it finds to generate
|
* address, then resets it.
|
||||||
* periodic interrupt transfers that report key presses. Initialises hcd and
|
*
|
||||||
* returns true if the device was successfully initialised and one or more
|
* \param base_addr - the base address of the device in virtual memory
|
||||||
* keyboards were found.
|
*
|
||||||
|
* \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
|
#endif // OHCI_H
|
||||||
|
|
19
system/pci.h
19
system/pci.h
|
@ -12,6 +12,25 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#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_BUS 256
|
||||||
#define PCI_MAX_DEV 32
|
#define PCI_MAX_DEV 32
|
||||||
#define PCI_MAX_FUNC 8
|
#define PCI_MAX_FUNC 8
|
||||||
|
|
|
@ -42,7 +42,7 @@ static const rgb_value_t vga_pallete[16] = {
|
||||||
{ 255, 255, 255 } // BOLD+WHITE
|
{ 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;
|
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].ch = ch;
|
||||||
shadow_buffer[row][col].attr = attr;
|
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)
|
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;
|
uint32_t b = ((vga_pallete[i].b * b_max) / 255) << screen_info->blue_pos;
|
||||||
lfb_pallete[i] = r | g | b;
|
lfb_pallete[i] = r | g | b;
|
||||||
}
|
}
|
||||||
|
} else if (screen_info->orig_video_isVGA != VIDEO_TYPE_NONE) {
|
||||||
|
vga_buffer = (vga_buffer_t *)(0xb8000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
115
system/serial.c
115
system/serial.c
|
@ -67,33 +67,24 @@ void serial_echo_print(const char *p)
|
||||||
if (!port->enable) {
|
if (!port->enable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now, do each character */
|
/* Now, do each character */
|
||||||
while (*p) {
|
while (*p) {
|
||||||
serial_wait_for_xmit(port);
|
|
||||||
|
|
||||||
/* Send the character out. */
|
/* Send the character out. */
|
||||||
serial_write_reg(port, UART_TX, *p);
|
serial_wait_for_xmit(port);
|
||||||
if (*p==10) {
|
serial_write_reg(port, UART_TX, *p++);
|
||||||
serial_wait_for_xmit(port);
|
|
||||||
serial_write_reg(port, UART_TX, 13);
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tty_print(int y, int x, const char *p)
|
void tty_goto(int y, int x)
|
||||||
{
|
{
|
||||||
static char sx[3], sy[3];
|
static char s[3];
|
||||||
|
|
||||||
itoa(++x,sx);
|
|
||||||
itoa(++y,sy);
|
|
||||||
|
|
||||||
serial_echo_print("\x1b[");
|
serial_echo_print("\x1b[");
|
||||||
serial_echo_print(sy);
|
serial_echo_print(itoa(y + 1, s));
|
||||||
serial_echo_print(";");
|
serial_echo_print(";");
|
||||||
serial_echo_print(sx);
|
serial_echo_print(itoa(x + 1, s));
|
||||||
serial_echo_print("H");
|
serial_echo_print("H");
|
||||||
serial_echo_print(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -135,8 +126,8 @@ void tty_init(void)
|
||||||
serial_write_reg(&console_serial, UART_LCR, lcr); /* Done with divisor */
|
serial_write_reg(&console_serial, UART_LCR, lcr); /* Done with divisor */
|
||||||
|
|
||||||
/* Prior to disabling interrupts, read the LSR and RBR registers */
|
/* Prior to disabling interrupts, read the LSR and RBR registers */
|
||||||
uart_status = serial_read_reg(&console_serial, UART_LSR); /* COM? LSR */
|
uart_status = serial_read_reg(&console_serial, UART_LSR); /* COM? LSR */
|
||||||
uart_status = serial_read_reg(&console_serial, UART_RX); /* COM? RBR */
|
uart_status = serial_read_reg(&console_serial, UART_RX); /* COM? RBR */
|
||||||
serial_write_reg(&console_serial, UART_IER, 0x00); /* Disable all interrupts */
|
serial_write_reg(&console_serial, UART_IER, 0x00); /* Disable all interrupts */
|
||||||
|
|
||||||
tty_clear_screen();
|
tty_clear_screen();
|
||||||
|
@ -146,7 +137,9 @@ void tty_init(void)
|
||||||
void tty_send_region(int start_row, int start_col, int end_row, int end_col)
|
void tty_send_region(int start_row, int start_col, int end_row, int end_col)
|
||||||
{
|
{
|
||||||
char p[SCREEN_WIDTH+1];
|
char p[SCREEN_WIDTH+1];
|
||||||
int col_len = end_col - start_col;
|
uint8_t ch;
|
||||||
|
int pos = 0;
|
||||||
|
int cur_inverse = -1, inverse = false;
|
||||||
|
|
||||||
if (start_col > (SCREEN_WIDTH - 1) || end_col > (SCREEN_WIDTH - 1)) {
|
if (start_col > (SCREEN_WIDTH - 1) || end_col > (SCREEN_WIDTH - 1)) {
|
||||||
return;
|
return;
|
||||||
|
@ -158,42 +151,64 @@ void tty_send_region(int start_row, int start_col, int end_row, int end_col)
|
||||||
|
|
||||||
for (int row = start_row; row <= end_row; row++) {
|
for (int row = start_row; row <= end_row; row++) {
|
||||||
|
|
||||||
// Last line is inverted (Black on white)
|
// Always use absolute positioning instead of relying on CR-LF to avoid issues
|
||||||
if (row == SCREEN_HEIGHT-1) {
|
// when a CR-LF is lost (especially with Industrial RS232/Ethernet converters).
|
||||||
tty_inverse();
|
tty_goto(row, start_col);
|
||||||
}
|
|
||||||
|
|
||||||
// Copy Shadow buffer to TTY buffer
|
// Copy Shadow buffer to TTY buffer
|
||||||
|
pos = 0;
|
||||||
for (int col = start_col; col <= end_col; col++) {
|
for (int col = start_col; col <= end_col; col++) {
|
||||||
p[col] = shadow_buffer[row][col].value & 0x7F;
|
|
||||||
|
inverse = ((shadow_buffer[row][col].attr & 0x70) >> 4 != BLUE);
|
||||||
|
|
||||||
|
if (cur_inverse != inverse) {
|
||||||
|
|
||||||
|
if (pos) {
|
||||||
|
p[pos] = '\0';
|
||||||
|
serial_echo_print(p);
|
||||||
|
pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inverse) {
|
||||||
|
tty_inverse();
|
||||||
|
} else {
|
||||||
|
tty_normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_inverse = inverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure only VT100 characters are sent. */
|
||||||
|
ch = shadow_buffer[row][col].ch;
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case 32 ... 127:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xB3:
|
||||||
|
ch = '|';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC1:
|
||||||
|
case 0xC2:
|
||||||
|
case 0xC4:
|
||||||
|
ch = '-';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xF8:
|
||||||
|
ch = '*';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ch = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
p[pos++] = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add string terminator
|
if (pos) {
|
||||||
p[end_col+1] = '\0';
|
p[pos] = '\0';
|
||||||
|
serial_echo_print(p);
|
||||||
// For first line, title on top-left must be inverted
|
|
||||||
// Do the switch, send to TTY then continue to next line.
|
|
||||||
if (row == 0 && start_col == 0 && col_len > 28) {
|
|
||||||
tty_inverse();
|
|
||||||
p[28] = '\0';
|
|
||||||
tty_print(row,0,p);
|
|
||||||
tty_normal();
|
|
||||||
p[28] = '|';
|
|
||||||
tty_print(row, 28, p + 28);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace degree symbol with '*' for tty to avoid a C437/VT100 translation table.
|
|
||||||
if (row == 1 && (shadow_buffer[1][25].value & 0xFF) == 0xF8) {
|
|
||||||
p[25] = 0x2A;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send row to TTY
|
|
||||||
tty_print(row, start_col, p + start_col);
|
|
||||||
|
|
||||||
// Revert to normal if last line.
|
|
||||||
if (row == SCREEN_HEIGHT-1) {
|
|
||||||
tty_normal();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ extern struct mem_dev *dmi_memory_device;
|
||||||
int smbios_init(void);
|
int smbios_init(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print DMI
|
* Print DMI
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void print_smbios_startup_info(void);
|
void print_smbios_startup_info(void);
|
||||||
|
|
1302
system/smbus.c
1302
system/smbus.c
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
* Provides functions for reading SPD via SMBUS
|
* Provides functions for reading SPD via SMBUS
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004-2022 Samuel Demeulemeester.
|
* Copyright (C) 2004-2023 Sam Demeulemeester.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define I2C_WRITE 0
|
#define I2C_WRITE 0
|
||||||
|
@ -74,7 +74,45 @@
|
||||||
#define NVSMBSTS_RES 0x20
|
#define NVSMBSTS_RES 0x20
|
||||||
#define NVSMBSTS_STATUS 0x1f
|
#define NVSMBSTS_STATUS 0x1f
|
||||||
|
|
||||||
struct pci_smbus_controller{
|
/* 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 vendor;
|
||||||
unsigned device;
|
unsigned device;
|
||||||
void (*get_adr)(void);
|
void (*get_adr)(void);
|
||||||
|
@ -86,14 +124,14 @@ typedef struct spd_infos {
|
||||||
uint16_t jedec_code;
|
uint16_t jedec_code;
|
||||||
uint32_t module_size;
|
uint32_t module_size;
|
||||||
char *type;
|
char *type;
|
||||||
uint8_t sku[32];
|
char sku[SPD_SKU_LEN + 1];
|
||||||
uint8_t sku_len;
|
|
||||||
uint8_t XMP;
|
uint8_t XMP;
|
||||||
uint16_t freq;
|
uint16_t freq;
|
||||||
bool hasECC;
|
bool hasECC;
|
||||||
uint8_t fab_year;
|
uint8_t fab_year;
|
||||||
uint8_t fab_week;
|
uint8_t fab_week;
|
||||||
uint16_t tCL;
|
uint16_t tCL;
|
||||||
|
uint8_t tCL_dec;
|
||||||
uint16_t tRCD;
|
uint16_t tRCD;
|
||||||
uint16_t tRP;
|
uint16_t tRP;
|
||||||
uint16_t tRAS;
|
uint16_t tRAS;
|
||||||
|
@ -103,6 +141,7 @@ typedef struct spd_infos {
|
||||||
typedef struct ram_infos {
|
typedef struct ram_infos {
|
||||||
uint16_t freq;
|
uint16_t freq;
|
||||||
uint16_t tCL;
|
uint16_t tCL;
|
||||||
|
uint8_t tCL_dec;
|
||||||
uint16_t tRCD;
|
uint16_t tRCD;
|
||||||
uint16_t tRP;
|
uint16_t tRP;
|
||||||
uint16_t tRAS;
|
uint16_t tRAS;
|
||||||
|
@ -117,4 +156,4 @@ extern ram_info ram;
|
||||||
|
|
||||||
void print_smbus_startup_info(void);
|
void print_smbus_startup_info(void);
|
||||||
|
|
||||||
#endif // SMBUS_H
|
#endif // SMBUS_H
|
||||||
|
|
247
system/smp.c
247
system/smp.c
|
@ -1,11 +1,10 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (C) 2020-2022 Martin Whitaker.
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
//
|
//
|
||||||
// Derived from an extract of memtest86+ smp.c:
|
// Derived from an extract of memtest86+ smp.c:
|
||||||
//
|
//
|
||||||
// MemTest86+ V5 Specific code (GPL V2.0)
|
// MemTest86+ V5 Specific code (GPL V2.0)
|
||||||
// By Samuel DEMEULEMEESTER, sdemeule@memtest.org
|
|
||||||
// http://www.canardpc.com - http://www.memtest.org
|
|
||||||
// ------------------------------------------------
|
// ------------------------------------------------
|
||||||
// smp.c - MemTest-86 Version 3.5
|
// smp.c - MemTest-86 Version 3.5
|
||||||
//
|
//
|
||||||
|
@ -15,15 +14,17 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
#include "boot.h"
|
#include "boot.h"
|
||||||
#include "bootparams.h"
|
#include "bootparams.h"
|
||||||
#include "efi.h"
|
#include "efi.h"
|
||||||
|
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
|
#include "heap.h"
|
||||||
|
#include "hwquirks.h"
|
||||||
#include "memrw32.h"
|
#include "memrw32.h"
|
||||||
#include "memsize.h"
|
#include "memsize.h"
|
||||||
#include "msr.h"
|
#include "msr.h"
|
||||||
#include "pmem.h"
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
#include "vmem.h"
|
#include "vmem.h"
|
||||||
|
@ -75,18 +76,8 @@
|
||||||
// Table signatures
|
// Table signatures
|
||||||
|
|
||||||
#define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24))
|
#define FPSignature ('_' | ('M' << 8) | ('P' << 16) | ('_' << 24))
|
||||||
|
|
||||||
#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24))
|
#define MPCSignature ('P' | ('C' << 8) | ('M' << 16) | ('P' << 24))
|
||||||
|
|
||||||
#define RSDPSignature1 ('R' | ('S' << 8) | ('D' << 16) | (' ' << 24))
|
|
||||||
#define RSDPSignature2 ('P' | ('T' << 8) | ('R' << 16) | (' ' << 24))
|
|
||||||
|
|
||||||
#define RSDTSignature ('R' | ('S' << 8) | ('D' << 16) | ('T' << 24))
|
|
||||||
|
|
||||||
#define XSDTSignature ('X' | ('S' << 8) | ('D' << 16) | ('T' << 24))
|
|
||||||
|
|
||||||
#define MADTSignature ('A' | ('P' << 8) | ('I' << 16) | ('C' << 24))
|
|
||||||
|
|
||||||
// MP config table entry types
|
// MP config table entry types
|
||||||
|
|
||||||
#define MP_PROCESSOR 0
|
#define MP_PROCESSOR 0
|
||||||
|
@ -189,30 +180,6 @@ typedef struct {
|
||||||
uint8_t dst_apic_lint;
|
uint8_t dst_apic_lint;
|
||||||
} mp_local_interrupt_entry_t;
|
} mp_local_interrupt_entry_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char signature[8]; // "RSD PTR "
|
|
||||||
uint8_t checksum;
|
|
||||||
char oem_id[6];
|
|
||||||
uint8_t revision;
|
|
||||||
uint32_t rsdt_addr;
|
|
||||||
uint32_t length;
|
|
||||||
uint64_t xsdt_addr;
|
|
||||||
uint8_t xchecksum;
|
|
||||||
uint8_t reserved[3];
|
|
||||||
} rsdp_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char signature[4]; // "RSDT" or "XSDT"
|
|
||||||
uint32_t length;
|
|
||||||
uint8_t revision;
|
|
||||||
uint8_t checksum;
|
|
||||||
char oem_id[6];
|
|
||||||
char oem_table_id[8];
|
|
||||||
char oem_revision[4];
|
|
||||||
char creator_id[4];
|
|
||||||
char creator_revision[4];
|
|
||||||
} rsdt_header_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char signature[4]; // "APIC"
|
char signature[4]; // "APIC"
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
|
@ -251,9 +218,6 @@ typedef struct {
|
||||||
// Private Variables
|
// Private Variables
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static const efi_guid_t EFI_ACPI_1_RDSP_GUID = { 0xeb9d2d30, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} };
|
|
||||||
static const efi_guid_t EFI_ACPI_2_RDSP_GUID = { 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81} };
|
|
||||||
|
|
||||||
static apic_register_t *apic = NULL;
|
static apic_register_t *apic = NULL;
|
||||||
|
|
||||||
static uint8_t apic_id_to_cpu_num[MAX_APIC_IDS];
|
static uint8_t apic_id_to_cpu_num[MAX_APIC_IDS];
|
||||||
|
@ -270,10 +234,6 @@ static uintptr_t alloc_addr = 0;
|
||||||
|
|
||||||
int num_available_cpus = 1; // There is always at least one CPU, the BSP
|
int num_available_cpus = 1; // There is always at least one CPU, the BSP
|
||||||
|
|
||||||
const char *rsdp_source = "";
|
|
||||||
|
|
||||||
uintptr_t rsdp_addr = 0;
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Private Functions
|
// Private Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -293,24 +253,13 @@ static uint32_t apic_read(int reg)
|
||||||
return read32(&apic[reg][0]);
|
return read32(&apic[reg][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checksum(const void *data, int length)
|
|
||||||
{
|
|
||||||
uint8_t sum = 0;
|
|
||||||
|
|
||||||
uint8_t *ptr = (uint8_t *)data;
|
|
||||||
while (length--) {
|
|
||||||
sum += *ptr++;
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
static floating_pointer_struct_t *scan_for_floating_ptr_struct(uintptr_t addr, int length)
|
static floating_pointer_struct_t *scan_for_floating_ptr_struct(uintptr_t addr, int length)
|
||||||
{
|
{
|
||||||
uint32_t *ptr = (uint32_t *)addr;
|
uint32_t *ptr = (uint32_t *)addr;
|
||||||
uint32_t *end = ptr + length / sizeof(uint32_t);
|
uint32_t *end = ptr + length / sizeof(uint32_t);
|
||||||
|
|
||||||
while (ptr < end) {
|
while (ptr < end) {
|
||||||
if (*ptr == FPSignature && checksum(ptr, 16) == 0) {
|
if (*ptr == FPSignature && acpi_checksum(ptr, 16) == 0) {
|
||||||
floating_pointer_struct_t *fp = (floating_pointer_struct_t *)ptr;
|
floating_pointer_struct_t *fp = (floating_pointer_struct_t *)ptr;
|
||||||
if (fp->length == 1 && (fp->spec_rev == 1 || fp->spec_rev == 4)) {
|
if (fp->length == 1 && (fp->spec_rev == 1 || fp->spec_rev == 4)) {
|
||||||
return fp;
|
return fp;
|
||||||
|
@ -329,7 +278,7 @@ static bool read_mp_config_table(uintptr_t addr)
|
||||||
mpc = (mp_config_table_header_t *)map_region(addr, mpc->length, true);
|
mpc = (mp_config_table_header_t *)map_region(addr, mpc->length, true);
|
||||||
if (mpc == NULL) return false;
|
if (mpc == NULL) return false;
|
||||||
|
|
||||||
if (mpc->signature != MPCSignature || checksum(mpc, mpc->length) != 0) {
|
if (mpc->signature != MPCSignature || acpi_checksum(mpc, mpc->length) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,32 +375,19 @@ static bool find_cpus_in_floating_mp_struct(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rsdp_t *scan_for_rsdp(uintptr_t addr, int length)
|
static bool find_cpus_in_madt(void)
|
||||||
{
|
{
|
||||||
uint32_t *ptr = (uint32_t *)addr;
|
if (acpi_config.madt_addr == 0) {
|
||||||
uint32_t *end = ptr + length / sizeof(uint32_t);
|
return false;
|
||||||
|
|
||||||
while (ptr < end) {
|
|
||||||
rsdp_t *rp = (rsdp_t *)ptr;
|
|
||||||
if (*ptr == RSDPSignature1 && *(ptr+1) == RSDPSignature2 && checksum(ptr, 20) == 0) {
|
|
||||||
if (rp->revision < 2 || (rp->length < 1024 && checksum(ptr, rp->length) == 0)) {
|
|
||||||
return rp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ptr += 4;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parse_madt(uintptr_t addr)
|
madt_table_header_t *mpc = (madt_table_header_t *)map_region(acpi_config.madt_addr, sizeof(madt_table_header_t), true);
|
||||||
{
|
|
||||||
madt_table_header_t *mpc = (madt_table_header_t *)map_region(addr, sizeof(madt_table_header_t), true);
|
|
||||||
if (mpc == NULL) return false;
|
if (mpc == NULL) return false;
|
||||||
|
|
||||||
mpc = (madt_table_header_t *)map_region(addr, mpc->length, true);
|
mpc = (madt_table_header_t *)map_region(acpi_config.madt_addr, mpc->length, true);
|
||||||
if (mpc == NULL) return false;
|
if (mpc == NULL) return false;
|
||||||
|
|
||||||
if (checksum(mpc, mpc->length) != 0) {
|
if (acpi_checksum(mpc, mpc->length) != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,150 +427,6 @@ static bool parse_madt(uintptr_t addr)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __x86_64__
|
|
||||||
static rsdp_t *find_rsdp_in_efi64_system_table(efi64_system_table_t *system_table)
|
|
||||||
{
|
|
||||||
efi64_config_table_t *config_tables = (efi64_config_table_t *)map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi64_config_table_t), true);
|
|
||||||
if (config_tables == NULL) return NULL;
|
|
||||||
|
|
||||||
uintptr_t table_addr = 0;
|
|
||||||
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (rsdp_t *)table_addr;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static rsdp_t *find_rsdp_in_efi32_system_table(efi32_system_table_t *system_table)
|
|
||||||
{
|
|
||||||
efi32_config_table_t *config_tables = (efi32_config_table_t *)map_region(system_table->config_tables, system_table->num_config_tables * sizeof(efi32_config_table_t), true);
|
|
||||||
if (config_tables == NULL) return NULL;
|
|
||||||
|
|
||||||
uintptr_t table_addr = 0;
|
|
||||||
for (uint32_t i = 0; i < system_table->num_config_tables; i++) {
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_2_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (memcmp(&config_tables[i].guid, &EFI_ACPI_1_RDSP_GUID, sizeof(efi_guid_t)) == 0) {
|
|
||||||
table_addr = config_tables[i].table;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (rsdp_t *)table_addr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool find_cpus_in_rsdp(void)
|
|
||||||
{
|
|
||||||
const boot_params_t *boot_params = (boot_params_t *)boot_params_addr;
|
|
||||||
|
|
||||||
const efi_info_t *efi_info = &boot_params->efi_info;
|
|
||||||
|
|
||||||
// Search for the RSDP
|
|
||||||
rsdp_t *rp = NULL;
|
|
||||||
#ifdef __x86_64__
|
|
||||||
if (efi_info->loader_signature == EFI64_LOADER_SIGNATURE) {
|
|
||||||
uintptr_t system_table_addr = (uintptr_t)efi_info->sys_tab_hi << 32 | (uintptr_t)efi_info->sys_tab;
|
|
||||||
system_table_addr = map_region(system_table_addr, sizeof(efi64_system_table_t), true);
|
|
||||||
if (system_table_addr != 0) {
|
|
||||||
rp = find_rsdp_in_efi64_system_table((efi64_system_table_t *)system_table_addr);
|
|
||||||
if (rp) rsdp_source = "EFI64 system table";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (efi_info->loader_signature == EFI32_LOADER_SIGNATURE) {
|
|
||||||
uintptr_t system_table_addr = map_region(efi_info->sys_tab, sizeof(efi32_system_table_t), true);
|
|
||||||
if (system_table_addr != 0) {
|
|
||||||
rp = find_rsdp_in_efi32_system_table((efi32_system_table_t *)system_table_addr);
|
|
||||||
if (rp) rsdp_source = "EFI32 system table";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (rp == NULL) {
|
|
||||||
// Search the BIOS EBDA area.
|
|
||||||
uintptr_t address = *(uint16_t *)0x40E << 4;
|
|
||||||
if (address) {
|
|
||||||
rp = scan_for_rsdp(address, 0x400);
|
|
||||||
if (rp) rsdp_source = "BIOS EBDA";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rp == NULL) {
|
|
||||||
// Search the BIOS reserved area.
|
|
||||||
rp = scan_for_rsdp(0xE0000, 0x20000);
|
|
||||||
if (rp) rsdp_source = "BIOS reserved area";
|
|
||||||
}
|
|
||||||
if (rp == NULL) {
|
|
||||||
// RSDP not found, give up.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rsdp_addr = (uintptr_t)rp;
|
|
||||||
|
|
||||||
// Found the RSDP, now get either the RSDT or XSDT and scan it for a pointer to the MADT.
|
|
||||||
rsdt_header_t *rt;
|
|
||||||
if (rp->revision >= 2) {
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, sizeof(rsdt_header_t), true);
|
|
||||||
if (rt == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Validate the XSDT.
|
|
||||||
if (*(uint32_t *)rt != XSDTSignature) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->xsdt_addr, rt->length, true);
|
|
||||||
if (rt == NULL || checksum(rt, rt->length) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Scan the XSDT for a pointer to the MADT.
|
|
||||||
uint64_t *tab_ptr = (uint64_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
|
||||||
uint64_t *tab_end = (uint64_t *)((uint8_t *)rt + rt->length);
|
|
||||||
|
|
||||||
while (tab_ptr < tab_end) {
|
|
||||||
uintptr_t addr = *tab_ptr++; // read the next table entry
|
|
||||||
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
|
||||||
|
|
||||||
if (ptr && *ptr == MADTSignature) {
|
|
||||||
if (parse_madt(addr)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, sizeof(rsdt_header_t), true);
|
|
||||||
if (rt == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Validate the RSDT.
|
|
||||||
if (*(uint32_t *)rt != RSDTSignature) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rt = (rsdt_header_t *)map_region(rp->rsdt_addr, rt->length, true);
|
|
||||||
if (rt == NULL || checksum(rt, rt->length) != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Scan the RSDT for a pointer to the MADT.
|
|
||||||
uint32_t *tab_ptr = (uint32_t *)((uint8_t *)rt + sizeof(rsdt_header_t));
|
|
||||||
uint32_t *tab_end = (uint32_t *)((uint8_t *)rt + rt->length);
|
|
||||||
|
|
||||||
while (tab_ptr < tab_end) {
|
|
||||||
uintptr_t addr = *tab_ptr++; // read the next table entry
|
|
||||||
uint32_t *ptr = (uint32_t *)map_region(addr, sizeof(uint32_t), true);
|
|
||||||
|
|
||||||
if (ptr && *ptr == MADTSignature) {
|
|
||||||
if (parse_madt(addr)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void send_ipi(int apic_id, int trigger, int level, int mode, uint8_t vector)
|
static inline void send_ipi(int apic_id, int trigger, int level, int mode, uint8_t vector)
|
||||||
{
|
{
|
||||||
apic_write(APIC_REG_ICRHI, apic_id << 24);
|
apic_write(APIC_REG_ICRHI, apic_id << 24);
|
||||||
|
@ -671,7 +463,8 @@ static uint32_t read_apic_esr(bool is_p5)
|
||||||
|
|
||||||
static bool start_cpu(int cpu_num)
|
static bool start_cpu(int cpu_num)
|
||||||
{
|
{
|
||||||
// This is based on the method used in Linux 5.14. We don't support non-integrated APICs, so can simplify it a bit.
|
// This is based on the method used in Linux 5.14.
|
||||||
|
// We don't support non-integrated APICs, so can simplify it a bit.
|
||||||
|
|
||||||
int apic_id = cpu_num_to_apic_id[cpu_num];
|
int apic_id = cpu_num_to_apic_id[cpu_num];
|
||||||
|
|
||||||
|
@ -747,8 +540,14 @@ void smp_init(bool smp_enable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process SMP Quirks
|
||||||
|
if (quirk.type & QUIRK_TYPE_SMP) {
|
||||||
|
// quirk.process();
|
||||||
|
smp_enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (smp_enable) {
|
if (smp_enable) {
|
||||||
(void)(find_cpus_in_rsdp() || find_cpus_in_floating_mp_struct());
|
(void)(find_cpus_in_madt() || find_cpus_in_floating_mp_struct());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,9 +555,9 @@ void smp_init(bool smp_enable)
|
||||||
apic_id_to_cpu_num[cpu_num_to_apic_id[i]] = i;
|
apic_id_to_cpu_num[cpu_num_to_apic_id[i]] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve last page of first segment for AP trampoline and sync objects.
|
// Allocate a page of low memory for AP trampoline and sync objects.
|
||||||
// These need to remain pinned in place during relocation.
|
// These need to remain pinned in place during relocation.
|
||||||
smp_heap_page = --pm_map[0].end;
|
smp_heap_page = heap_alloc(HEAP_TYPE_LM_1, PAGE_SIZE, PAGE_SIZE) >> PAGE_SHIFT;
|
||||||
|
|
||||||
ap_startup_addr = (uintptr_t)startup;
|
ap_startup_addr = (uintptr_t)startup;
|
||||||
|
|
||||||
|
|
|
@ -38,15 +38,6 @@ typedef enum __attribute__ ((packed)) {
|
||||||
*/
|
*/
|
||||||
extern int num_available_cpus;
|
extern int num_available_cpus;
|
||||||
|
|
||||||
/**
|
|
||||||
* The search step that located the ACPI RSDP (for debug).
|
|
||||||
*/
|
|
||||||
extern const char *rsdp_source;
|
|
||||||
/**
|
|
||||||
* The address of the ACPI RSDP (for debug).
|
|
||||||
*/
|
|
||||||
extern uintptr_t rsdp_addr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the SMP state and detects the number of available CPU cores.
|
* Initialises the SMP state and detects the number of available CPU cores.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
// Copyright (C) 2020-2022 Martin Whitaker.
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2023 Sam Demeulemeester.
|
||||||
//
|
//
|
||||||
// Derived from an extract of memtest86+ init.c:
|
// Derived from an extract of memtest86+ init.c:
|
||||||
//
|
//
|
||||||
|
@ -16,60 +17,120 @@
|
||||||
|
|
||||||
#include "cpuid.h"
|
#include "cpuid.h"
|
||||||
#include "cpuinfo.h"
|
#include "cpuinfo.h"
|
||||||
|
#include "hwquirks.h"
|
||||||
#include "msr.h"
|
#include "msr.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
#include "temperature.h"
|
#include "temperature.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Public Variables
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
float cpu_temp_offset = 0;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Public Functions
|
// Public Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
int get_cpu_temperature(void)
|
static int TjMax = 0;
|
||||||
|
|
||||||
|
void get_specific_TjMax(void)
|
||||||
{
|
{
|
||||||
if (imc_type == 0) {
|
// The TjMax value for some Mobile/Embedded CPUs must be read from a fixed
|
||||||
return 0;
|
// 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
|
// Get TjMax for Intel CPU
|
||||||
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6) {
|
if (cpuid_info.vendor_id.str[0] == 'G' && cpuid_info.max_cpuid >= 6 && (cpuid_info.dts_pmp & 1)) {
|
||||||
if (cpuid_info.dts_pmp & 1) {
|
|
||||||
uint32_t msrl, msrh;
|
|
||||||
|
|
||||||
rdmsr(MSR_IA32_THERM_STATUS, msrl, msrh);
|
get_specific_TjMax();
|
||||||
int Tabs = (msrl >> 16) & 0x7F;
|
|
||||||
|
|
||||||
rdmsr(MSR_IA32_TEMPERATURE_TARGET, msrl, msrh);
|
if (TjMax == 0) {
|
||||||
int Tjunc = (msrl >> 16) & 0x7F;
|
// Generic Method using MSR 0x1A2
|
||||||
|
rdmsr(MSR_IA32_TEMPERATURE_TARGET, regl, regh);
|
||||||
|
TjMax = (regl >> 16) & 0x7F;
|
||||||
|
|
||||||
if (Tjunc < 50 || Tjunc > 125) {
|
if (TjMax < 50 || TjMax > 125) {
|
||||||
Tjunc = 90;
|
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
|
// 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
|
if (cpuid_info.version.extendedFamily >= 8) { // Target Zen µarch and newer. Use SMN to get temperature.
|
||||||
uint32_t rtcr = pci_config_read32(0, 24, 3, 0xA4);
|
|
||||||
int raw_temp = (rtcr >> 21) & 0x7FF;
|
|
||||||
|
|
||||||
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
|
return cpu_temp_offset + 0.125f * (float)((regl >> 21) & 0x7FF);
|
||||||
uint32_t tval = amd_smn_read(SMN_THM_TCON_CUR_TMP);
|
|
||||||
|
|
||||||
float offset = 0;
|
} else if (cpuid_info.version.extendedFamily > 0) { // Target K10 to K15 (Bulldozer)
|
||||||
|
|
||||||
if((tval >> 19) & 0x01) {
|
regl = pci_config_read32(0, 24, 3, AMD_TEMP_REG_K10);
|
||||||
offset = -49.0f;
|
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;
|
return 0;
|
||||||
|
|
|
@ -8,8 +8,22 @@
|
||||||
*
|
*
|
||||||
*//*
|
*//*
|
||||||
* Copyright (C) 2020-2022 Martin Whitaker.
|
* 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
|
* Returns the current temperature of the CPU. Returns 0 if
|
||||||
* the temperature cannot be read.
|
* the temperature cannot be read.
|
||||||
|
|
96
system/timers.c
Normal file
96
system/timers.c
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
// Copyright (C) 2004-2022 Sam Demeulemeester.
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "acpi.h"
|
||||||
|
#include "cpuid.h"
|
||||||
|
#include "cpuinfo.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "tsc.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define PIT_TICKS_50mS 59659 // PIT clock is 1.193182MHz
|
||||||
|
#define APIC_TICKS_50mS 178977 // APIC clock is 3.579545MHz
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Private Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void correct_tsc(void)
|
||||||
|
{
|
||||||
|
uint32_t start_time, end_time, run_time, counter;
|
||||||
|
int loops = 0;
|
||||||
|
|
||||||
|
if (cpuid_info.flags.rdtsc == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If available, use APIC Timer to find TSC correction factor
|
||||||
|
if (acpi_config.pm_is_io && acpi_config.pm_addr != 0) {
|
||||||
|
rdtscl(start_time);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (inl(acpi_config.pm_addr) > (counter + APIC_TICKS_50mS) || loops > 1000000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
loops++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rdtscl(end_time);
|
||||||
|
|
||||||
|
run_time = end_time - start_time;
|
||||||
|
|
||||||
|
// Make sure we have a credible result
|
||||||
|
if (loops >= 10 && run_time >= 50000) {
|
||||||
|
clks_per_msec = run_time / 50;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use PIT Timer to find TSC correction factor if APIC not available
|
||||||
|
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
|
||||||
|
outb(0xb0, 0x43);
|
||||||
|
outb(PIT_TICKS_50mS & 0xff, 0x42);
|
||||||
|
outb(PIT_TICKS_50mS >> 8, 0x42);
|
||||||
|
|
||||||
|
rdtscl(start_time);
|
||||||
|
|
||||||
|
loops = 0;
|
||||||
|
do {
|
||||||
|
loops++;
|
||||||
|
} while ((inb(0x61) & 0x20) == 0);
|
||||||
|
|
||||||
|
rdtscl(end_time);
|
||||||
|
|
||||||
|
run_time = end_time - start_time;
|
||||||
|
|
||||||
|
// Make sure we have a credible result
|
||||||
|
if (loops >= 4 && run_time >= 50000) {
|
||||||
|
clks_per_msec = run_time / 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Public Functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void timers_init(void)
|
||||||
|
{
|
||||||
|
correct_tsc();
|
||||||
|
}
|
20
system/timers.h
Normal file
20
system/timers.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
#ifndef _TIMERS_H_
|
||||||
|
#define _TIMERS_H_
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
*
|
||||||
|
* Provides support for various timers sources
|
||||||
|
*
|
||||||
|
*//*
|
||||||
|
* Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
|
* Copyright (C) 2004-2022 Sam Demeulemeester
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize timers (to correct TSC frequency)
|
||||||
|
*/
|
||||||
|
void timers_init(void);
|
||||||
|
|
||||||
|
#endif /* _TIMERS_H_ */
|
|
@ -5,11 +5,11 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "heap.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "memrw32.h"
|
#include "memrw32.h"
|
||||||
#include "memsize.h"
|
#include "memsize.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
#include "pmem.h"
|
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
#define UHCI_USBCMD_GR 0x0004 // Global Reset
|
#define UHCI_USBCMD_GR 0x0004 // Global Reset
|
||||||
#define UHCI_USBCMD_MAXP 0x0080 // Max Packet
|
#define UHCI_USBCMD_MAXP 0x0080 // Max Packet
|
||||||
|
|
||||||
// USB Status register
|
// USB Status register
|
||||||
|
|
||||||
#define UHCI_USBSTS_INT 0x0001 // Interrupt
|
#define UHCI_USBSTS_INT 0x0001 // Interrupt
|
||||||
#define UHCI_USBSTS_ERR 0x0002 // Error interrupt
|
#define UHCI_USBSTS_ERR 0x0002 // Error interrupt
|
||||||
|
@ -195,11 +195,6 @@ typedef struct {
|
||||||
// Private Functions
|
// Private Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static size_t num_pages(size_t size)
|
|
||||||
{
|
|
||||||
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool io_wait_until_clr(uint16_t io_reg, uint16_t bit_mask, int max_time)
|
static bool io_wait_until_clr(uint16_t io_reg, uint16_t bit_mask, int max_time)
|
||||||
{
|
{
|
||||||
int timer = max_time >> 3;
|
int timer = max_time >> 3;
|
||||||
|
@ -425,7 +420,7 @@ static const hcd_methods_t methods = {
|
||||||
// Public Functions
|
// 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.
|
// Disable PCI and SMM interrupts.
|
||||||
pci_config_write16(bus, dev, func, UHCI_LEGSUP, UHCI_LEGSUP_CLEAR);
|
pci_config_write16(bus, dev, func, UHCI_LEGSUP, UHCI_LEGSUP_CLEAR);
|
||||||
|
@ -434,16 +429,26 @@ 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 (!halt_host_controller(io_base)) return false;
|
||||||
if (!reset_host_controller(io_base)) return false;
|
if (!reset_host_controller(io_base)) return false;
|
||||||
|
|
||||||
// Allocate and initialise the frame list. This needs to be aligned on a 4K page boundary.
|
return true;
|
||||||
pm_map[0].end -= num_pages(UHCI_FL_LENGTH * sizeof(uint32_t));
|
}
|
||||||
uintptr_t fl_addr = pm_map[0].end << PAGE_SHIFT;
|
|
||||||
|
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 = heap_mark(HEAP_TYPE_LM_1);
|
||||||
|
|
||||||
|
// Allocate the frame list. This needs to be aligned on a 4K page boundary.
|
||||||
|
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;
|
uint32_t *fl = (uint32_t *)fl_addr;
|
||||||
|
|
||||||
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory,
|
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||||
// so allocate it in the first segment.
|
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||||
// TODO: check for segment overflow.
|
if (workspace_addr == 0) {
|
||||||
pm_map[0].end -= num_pages(sizeof(workspace_t));
|
goto no_keyboards_found;
|
||||||
uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT;
|
}
|
||||||
workspace_t *ws = (workspace_t *)workspace_addr;
|
workspace_t *ws = (workspace_t *)workspace_addr;
|
||||||
|
|
||||||
memset(ws, 0, sizeof(workspace_t));
|
memset(ws, 0, sizeof(workspace_t));
|
||||||
|
@ -469,18 +474,14 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
|
||||||
outl(fl_addr, UHCI_FLBASE);
|
outl(fl_addr, UHCI_FLBASE);
|
||||||
outb(UHCI_SOF_DEFAULT, UHCI_SOF);
|
outb(UHCI_SOF_DEFAULT, UHCI_SOF);
|
||||||
if (!start_host_controller(io_base)) {
|
if (!start_host_controller(io_base)) {
|
||||||
pm_map[0].end += num_pages(sizeof(workspace_t));
|
goto no_keyboards_found;
|
||||||
pm_map[0].end += num_pages(UHCI_FL_LENGTH * sizeof(uint32_t));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a hub descriptor for the root hub.
|
// Construct a hub descriptor for the root hub.
|
||||||
usb_hub_t root_hub;
|
usb_hub_t root_hub;
|
||||||
|
memset(&root_hub, 0, sizeof(root_hub));
|
||||||
root_hub.ep0 = NULL;
|
root_hub.ep0 = NULL;
|
||||||
root_hub.level = 0;
|
|
||||||
root_hub.route = 0;
|
|
||||||
root_hub.num_ports = MAX_UHCI_PORTS;
|
root_hub.num_ports = MAX_UHCI_PORTS;
|
||||||
root_hub.power_up_delay = 0;
|
|
||||||
|
|
||||||
usleep(100*MILLISEC); // USB maximum device attach time
|
usleep(100*MILLISEC); // USB maximum device attach time
|
||||||
|
|
||||||
|
@ -535,16 +536,8 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
|
||||||
num_keyboards, num_keyboards != 1 ? "s" : "");
|
num_keyboards, num_keyboards != 1 ? "s" : "");
|
||||||
|
|
||||||
if (num_keyboards == 0) {
|
if (num_keyboards == 0) {
|
||||||
// Halt the host controller.
|
|
||||||
(void)halt_host_controller(io_base);
|
(void)halt_host_controller(io_base);
|
||||||
|
goto no_keyboards_found;
|
||||||
// Deallocate the workspace for this controller.
|
|
||||||
pm_map[0].end += num_pages(sizeof(workspace_t));
|
|
||||||
|
|
||||||
// Deallocate the periodic frame list.
|
|
||||||
pm_map[0].end += num_pages(UHCI_FL_LENGTH * sizeof(uint32_t));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ws->num_keyboards = num_keyboards;
|
ws->num_keyboards = num_keyboards;
|
||||||
|
@ -582,4 +575,8 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
no_keyboards_found:
|
||||||
|
heap_rewind(HEAP_TYPE_LM_1, initial_heap_mark);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,35 @@
|
||||||
#include "usbhcd.h"
|
#include "usbhcd.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the UHCI device found at bus, dev, func on the PCI bus and
|
* If necessary, takes ownership of the UHCI device at the specified base
|
||||||
* io_base in the I/O address space, scans all the attached USB devices, and
|
* address, then resets it.
|
||||||
* configures any HID USB keyboard devices it finds to generate periodic
|
*
|
||||||
* interrupt transfers that report key presses. Initialises hcd and returns
|
* \param bus - the PCI bus number for accessing the device
|
||||||
* true if the device was successfully initialised and one or more keyboards
|
* \param dev - the PCI device number for accessing the device
|
||||||
* were found.
|
* \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
|
#endif // UHCI_H
|
||||||
|
|
235
system/usbhcd.c
235
system/usbhcd.c
|
@ -22,7 +22,9 @@
|
||||||
// Constants
|
// 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
|
#define PAUSE_IF_NONE_TIME 10 // seconds
|
||||||
|
|
||||||
|
@ -41,6 +43,15 @@ typedef enum {
|
||||||
MAX_HCI_TYPE = 4
|
MAX_HCI_TYPE = 4
|
||||||
} hci_type_t;
|
} 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
|
// 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.
|
// 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 },
|
{ &methods, NULL },
|
||||||
{ &methods, NULL },
|
{ &methods, NULL },
|
||||||
|
@ -71,7 +82,7 @@ static usb_hcd_t usb_controllers[MAX_USB_CONTROLLERS] = {
|
||||||
{ &methods, NULL }
|
{ &methods, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int num_usb_controllers = 0;
|
static int num_hcd = 0;
|
||||||
|
|
||||||
static int print_row = 0;
|
static int print_row = 0;
|
||||||
static int print_col = 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->num_ports = hub_desc.num_ports;
|
||||||
hub->tt_think_time = hub_desc.characteristics & 0x0060 >> 5;
|
hub->tt_think_time = hub_desc.characteristics & 0x0060 >> 5;
|
||||||
hub->power_up_delay = hub_desc.power_up_delay;
|
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);
|
usb_endpoint_desc_t *ep1_desc = find_hub_endpoint_descriptor(hcd->ws->data_buffer, hcd->ws->data_length);
|
||||||
if (ep1_desc == NULL) {
|
if (ep1_desc == NULL) {
|
||||||
return false;
|
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;
|
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 vendor_id = pci_config_read16(bus, dev, func, 0x00);
|
||||||
uint16_t device_id = pci_config_read16(bus, dev, func, 0x02);
|
uint16_t device_id = pci_config_read16(bus, dev, func, 0x02);
|
||||||
uint16_t pci_status = pci_config_read16(bus, dev, func, 0x06);
|
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.
|
// 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));
|
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],
|
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");
|
(uintptr_t)vendor_id, (uintptr_t)device_id, base_addr, mmio_size, in_io_space ? "I/O" : "Mem");
|
||||||
|
|
||||||
if (in_io_space) {
|
if (in_io_space) {
|
||||||
if (controller_type != UHCI) {
|
if (controller_type != UHCI) {
|
||||||
print_usb_info(" Unsupported address mapping for this controller type");
|
print_usb_info(" Unsupported address mapping for this controller type");
|
||||||
|
hci->type = NOT_HCI; // mark this controller as unusable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (controller_type == UHCI) {
|
if (controller_type == UHCI) {
|
||||||
print_usb_info(" Unsupported address mapping for this controller type");
|
print_usb_info(" Unsupported address mapping for this controller type");
|
||||||
|
hci->type = NOT_HCI; // mark this controller as unusable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
base_addr = map_region(base_addr, mmio_size, false);
|
base_addr = map_region(base_addr, mmio_size, false);
|
||||||
if (base_addr == 0) {
|
if (base_addr == 0) {
|
||||||
print_usb_info(" Failed to map device into virtual memory");
|
print_usb_info(" Failed to map device into virtual memory");
|
||||||
|
hci->type = NOT_HCI; // mark this controller as unusable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hci->vm_base_addr = base_addr;
|
||||||
|
|
||||||
// Search for power management capability.
|
// Search for power management capability.
|
||||||
//uint8_t pm_cap_ptr;
|
//uint8_t pm_cap_ptr;
|
||||||
if (pci_status & 0x10) {
|
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;
|
bool keyboards_found = false;
|
||||||
if (controller_type == UHCI) {
|
switch (controller_type) {
|
||||||
keyboards_found = uhci_init(bus, dev, func, base_addr, &usb_controllers[num_usb_controllers]);
|
case UHCI:
|
||||||
}
|
keyboards_found = uhci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||||
if (controller_type == OHCI) {
|
break;
|
||||||
keyboards_found = ohci_init(base_addr, &usb_controllers[num_usb_controllers]);
|
case OHCI:
|
||||||
}
|
keyboards_found = ohci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||||
if (controller_type == EHCI) {
|
break;
|
||||||
keyboards_found = ehci_init(bus, dev, func, base_addr, &usb_controllers[num_usb_controllers]);
|
case EHCI:
|
||||||
}
|
keyboards_found = ehci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||||
if (controller_type == XHCI) {
|
break;
|
||||||
keyboards_found = xhci_init(base_addr, &usb_controllers[num_usb_controllers]);
|
case XHCI:
|
||||||
|
keyboards_found = xhci_probe(vm_base_addr, &hcd_list[num_hcd]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (keyboards_found) {
|
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)));
|
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)
|
bool wait_until_clr(const volatile uint32_t *reg, uint32_t bit_mask, int max_time)
|
||||||
{
|
{
|
||||||
int timer = max_time >> 3;
|
int timer = max_time >> 3;
|
||||||
|
@ -543,12 +656,12 @@ bool assign_usb_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num
|
||||||
ep0->max_packet_size = default_max_packet_size(device_speed);
|
ep0->max_packet_size = default_max_packet_size(device_speed);
|
||||||
ep0->interval = 0;
|
ep0->interval = 0;
|
||||||
|
|
||||||
// The device should currently be in Default state. For loww and full speed devices, We first fetch the first
|
// The device should currently be in Default state. For low and full speed devices, we first fetch the first
|
||||||
// 8 bytes of the device descriptor to discover the maximum packet size for the control endpoint. We then set
|
// 8 bytes of the device descriptor to discover the maximum packet size for the control endpoint. We then set
|
||||||
// the device address, which moves the device into Address state, and fetch the full device descriptor.
|
// the device address, which moves the device into Address state, and fetch the full device descriptor.
|
||||||
|
|
||||||
size_t fetch_length = sizeof(usb_device_desc_t);
|
size_t fetch_length = sizeof(usb_device_desc_t);
|
||||||
if (device_speed < USB_SPEED_HIGH) {
|
if (device_speed < USB_SPEED_HIGH || usb_init_options & USB_2_STEP_INIT) {
|
||||||
fetch_length = 8;
|
fetch_length = 8;
|
||||||
goto fetch_descriptor;
|
goto fetch_descriptor;
|
||||||
}
|
}
|
||||||
|
@ -600,7 +713,7 @@ bool assign_usb_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find_attached_usb_keyboards(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num,
|
bool find_attached_usb_keyboards(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num,
|
||||||
usb_speed_t device_speed, int device_id, int *num_devices,
|
usb_speed_t device_speed, int device_id, int *num_devices,
|
||||||
usb_ep_t keyboards[], int max_keyboards, int *num_keyboards)
|
usb_ep_t keyboards[], int max_keyboards, int *num_keyboards)
|
||||||
{
|
{
|
||||||
|
@ -719,62 +832,40 @@ void find_usb_keyboards(bool pause_if_none)
|
||||||
clear_screen();
|
clear_screen();
|
||||||
print_usb_info("Scanning for USB keyboards...");
|
print_usb_info("Scanning for USB keyboards...");
|
||||||
|
|
||||||
num_usb_controllers = 0;
|
hci_info_t hci_list[MAX_HCI];
|
||||||
for (int bus = 0; bus < PCI_MAX_BUS; bus++) {
|
|
||||||
for (int dev = 0; dev < PCI_MAX_DEV; dev++) {
|
int num_hci = find_usb_controllers(hci_list);
|
||||||
hci_type_t controller_type[PCI_MAX_FUNC];
|
|
||||||
for (int func = 0; func < PCI_MAX_FUNC; func++) {
|
// Take ownership of all controllers and reset them.
|
||||||
controller_type[func] = NOT_HCI;
|
for (int i = 0; i < num_hci; i++) {
|
||||||
}
|
reset_usb_controller(&hci_list[i]);
|
||||||
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);
|
num_hcd = 0;
|
||||||
uint8_t hdr_type = pci_config_read8 (bus, dev, func, 0x0e);
|
|
||||||
if (vendor_id != 0xffff) {
|
// As we don't support hot plugging, we need to probe EHCI controllers before
|
||||||
// Test for a USB controller.
|
// probing any of their companion controllers, to ensure any low and full speed
|
||||||
uint16_t class_code = pci_config_read16(bus, dev, func, 0x0a);
|
// devices are routed to the companion controllers before we probe them.
|
||||||
if (class_code == 0x0c03) {
|
for (int i = 0; i < num_hci && num_hcd < MAX_HCD; i++) {
|
||||||
controller_type[func] = pci_config_read8(bus, dev, func, 0x09) >> 4;
|
if (hci_list[i].type == EHCI) {
|
||||||
// We need to initialise EHCI controllers before initialising any of their companion
|
if (~usb_init_options & USB_IGNORE_EHCI) {
|
||||||
// controllers, so do it now.
|
probe_usb_controller(EHCI, hci_list[i].pm_base_addr, hci_list[i].vm_base_addr);
|
||||||
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_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) {
|
if (usb_init_options & USB_DEBUG) {
|
||||||
print_usb_info("Press any key to continue...");
|
print_usb_info("Press any key to continue...");
|
||||||
while (get_key() == 0) {}
|
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--) {
|
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');
|
print_usb_info("No USB keyboards found. Continuing in %i second%c ", i, i == 1 ? ' ' : 's');
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
@ -785,10 +876,10 @@ void find_usb_keyboards(bool pause_if_none)
|
||||||
|
|
||||||
uint8_t get_usb_keycode(void)
|
uint8_t get_usb_keycode(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num_usb_controllers; i++) {
|
for (int i = 0; i < num_hcd; i++) {
|
||||||
const usb_hcd_t *hcd = &usb_controllers[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;
|
int kc_index_o = hcd->ws->kc_index_o;
|
||||||
if (kc_index_o != hcd->ws->kc_index_i) {
|
if (kc_index_o != hcd->ws->kc_index_i) {
|
||||||
|
|
|
@ -62,6 +62,14 @@ typedef struct __attribute__ ((packed)) {
|
||||||
uint8_t reserved;
|
uint8_t reserved;
|
||||||
} usb_ep_t;
|
} 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).
|
* 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 num_ports;
|
||||||
uint8_t tt_think_time;
|
uint8_t tt_think_time;
|
||||||
uint8_t power_up_delay;
|
uint8_t power_up_delay;
|
||||||
|
usb_parent_t hs_parent;
|
||||||
|
uint16_t reserved;
|
||||||
} usb_hub_t;
|
} usb_hub_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,7 +131,8 @@ typedef enum {
|
||||||
USB_DEFAULT_INIT = 0,
|
USB_DEFAULT_INIT = 0,
|
||||||
USB_EXTRA_RESET = 1 << 0,
|
USB_EXTRA_RESET = 1 << 0,
|
||||||
USB_IGNORE_EHCI = 1 << 1,
|
USB_IGNORE_EHCI = 1 << 1,
|
||||||
USB_DEBUG = 1 << 2
|
USB_2_STEP_INIT = 1 << 2,
|
||||||
|
USB_DEBUG = 1 << 3
|
||||||
} usb_init_options_t;
|
} usb_init_options_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -209,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);
|
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
|
* 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.
|
* to by reg or for max_time microseconds to elapse.
|
||||||
|
|
204
system/xhci.c
204
system/xhci.c
|
@ -4,9 +4,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "heap.h"
|
||||||
#include "memrw32.h"
|
#include "memrw32.h"
|
||||||
#include "memsize.h"
|
#include "memsize.h"
|
||||||
#include "pmem.h"
|
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "vmem.h"
|
#include "vmem.h"
|
||||||
|
|
||||||
|
@ -329,9 +329,11 @@ typedef struct {
|
||||||
uint32_t cr_enqueue_state;
|
uint32_t cr_enqueue_state;
|
||||||
uint32_t er_dequeue_state;
|
uint32_t er_dequeue_state;
|
||||||
|
|
||||||
// Transient values used during device enumeration and configuration.
|
// Input context for controller commands.
|
||||||
uintptr_t input_context_addr;
|
uintptr_t input_context_addr;
|
||||||
uintptr_t output_context_addr;
|
|
||||||
|
// Transient values used during device enumeration and configuration.
|
||||||
|
uintptr_t initial_heap_mark;
|
||||||
uintptr_t control_ep_tr_addr;
|
uintptr_t control_ep_tr_addr;
|
||||||
uintptr_t interrupt_ep_tr_addr;
|
uintptr_t interrupt_ep_tr_addr;
|
||||||
|
|
||||||
|
@ -342,26 +344,10 @@ typedef struct {
|
||||||
uint8_t kbd_ep_id [MAX_KEYBOARDS];
|
uint8_t kbd_ep_id [MAX_KEYBOARDS];
|
||||||
} workspace_t __attribute__ ((aligned (64)));
|
} workspace_t __attribute__ ((aligned (64)));
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// Private Variables
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// The heap segment of the physical memory map is used when allocating memory
|
|
||||||
// to the controller that we don't need to access during normal operation.
|
|
||||||
// Any memory we do need to access during normal operation is allocated from
|
|
||||||
// segment 0, which is permanently mapped into the virtual memory address space.
|
|
||||||
|
|
||||||
static int heap_segment = -1;
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Private Functions
|
// Private Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
static size_t num_pages(size_t size)
|
|
||||||
{
|
|
||||||
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t round_up(size_t size, size_t alignment)
|
static size_t round_up(size_t size, size_t alignment)
|
||||||
{
|
{
|
||||||
return (size + alignment - 1) & ~(alignment - 1);
|
return (size + alignment - 1) & ~(alignment - 1);
|
||||||
|
@ -658,37 +644,36 @@ static int allocate_slot(const usb_hcd_t *hcd)
|
||||||
|
|
||||||
xhci_trb_t event;
|
xhci_trb_t event;
|
||||||
|
|
||||||
// Allocate and initialise a private workspace for this device.
|
// Record the heap state to allow us to free memory.
|
||||||
// TODO: check for heap overflow.
|
ws->initial_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||||
|
|
||||||
pm_map[0].end -= num_pages(DEVICE_WS_SIZE);
|
// Allocate and initialise a private workspace for this device.
|
||||||
uintptr_t device_workspace_addr = pm_map[0].end << PAGE_SHIFT;
|
uintptr_t device_workspace_addr = heap_alloc(HEAP_TYPE_LM_1, DEVICE_WS_SIZE, PAGE_SIZE);
|
||||||
ws->output_context_addr = device_workspace_addr;
|
if (device_workspace_addr == 0) {
|
||||||
ws->control_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE;
|
goto free_memory;
|
||||||
ws->interrupt_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE + sizeof(ep_tr_t);
|
}
|
||||||
|
|
||||||
memset((void *)device_workspace_addr, 0, DEVICE_WS_SIZE);
|
memset((void *)device_workspace_addr, 0, DEVICE_WS_SIZE);
|
||||||
|
|
||||||
// Temporarily allocate and initialise the input context data structure on the heap.
|
ws->control_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE;
|
||||||
// As we only use this temporarily, there's no need to adjust pm_map.
|
ws->interrupt_ep_tr_addr = device_workspace_addr + XHCI_MAX_OP_CONTEXT_SIZE + sizeof(ep_tr_t);
|
||||||
|
|
||||||
ws->input_context_addr = device_workspace_addr - XHCI_MAX_IP_CONTEXT_SIZE;
|
|
||||||
|
|
||||||
memset((void *)ws->input_context_addr, 0, XHCI_MAX_IP_CONTEXT_SIZE);
|
|
||||||
|
|
||||||
// Allocate a device slot and set up its output context.
|
// Allocate a device slot and set up its output context.
|
||||||
|
|
||||||
enqueue_xhci_command(ws, XHCI_TRB_ENABLE_SLOT | XHCI_TRB_USB2_SLOT, 0, 0);
|
enqueue_xhci_command(ws, XHCI_TRB_ENABLE_SLOT | XHCI_TRB_USB2_SLOT, 0, 0);
|
||||||
ring_host_controller_doorbell(ws->db_regs);
|
ring_host_controller_doorbell(ws->db_regs);
|
||||||
if (wait_for_xhci_event(ws, XHCI_TRB_COMMAND_COMPLETE, 100*MILLISEC, &event) != XHCI_EVENT_CC_SUCCESS) {
|
if (wait_for_xhci_event(ws, XHCI_TRB_COMMAND_COMPLETE, 100*MILLISEC, &event) != XHCI_EVENT_CC_SUCCESS) {
|
||||||
pm_map[0].end += num_pages(DEVICE_WS_SIZE);
|
goto free_memory;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
int slot_id = event_slot_id(&event);
|
int slot_id = event_slot_id(&event);
|
||||||
|
|
||||||
write64(&ws->device_context_index[slot_id], ws->output_context_addr);
|
write64(&ws->device_context_index[slot_id], device_workspace_addr);
|
||||||
|
|
||||||
return slot_id;
|
return slot_id;
|
||||||
|
|
||||||
|
free_memory:
|
||||||
|
heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool release_slot(const usb_hcd_t *hcd, int slot_id)
|
static bool release_slot(const usb_hcd_t *hcd, int slot_id)
|
||||||
|
@ -705,7 +690,7 @@ static bool release_slot(const usb_hcd_t *hcd, int slot_id)
|
||||||
|
|
||||||
write64(&ws->device_context_index[slot_id], 0);
|
write64(&ws->device_context_index[slot_id], 0);
|
||||||
|
|
||||||
pm_map[0].end += num_pages(DEVICE_WS_SIZE);
|
heap_rewind(HEAP_TYPE_LM_1, ws->initial_heap_mark);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -733,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.
|
// 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;
|
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);
|
ctrl_context->add_context_flags = XHCI_CONTEXT_A(0) | XHCI_CONTEXT_A(1);
|
||||||
|
|
||||||
|
@ -742,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);
|
uint32_t route = usb_route(hub, port_num);
|
||||||
slot_context->params1 |= route & 0xfffff;
|
slot_context->params1 |= route & 0xfffff;
|
||||||
slot_context->root_hub_port_num = route >> 24;
|
slot_context->root_hub_port_num = route >> 24;
|
||||||
if (device_speed < USB_SPEED_HIGH && hub->ep0->device_speed == USB_SPEED_HIGH) {
|
usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed);
|
||||||
slot_context->parent_slot_id = hub->ep0->device_id;
|
slot_context->parent_slot_id = hs_parent.device_id;
|
||||||
slot_context->parent_port_num = port_num;
|
slot_context->parent_port_num = hs_parent.port_num;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
slot_context->root_hub_port_num = port_num;
|
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);
|
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->params2 = XHCI_EP_CONTROL << 3 | 3 << 1; // EP Type | CErr
|
||||||
ep_context->max_burst_size = 0;
|
ep_context->max_burst_size = 0;
|
||||||
|
@ -769,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);
|
size_t fetch_length = sizeof(usb_device_desc_t);
|
||||||
uint32_t command_flags = 0;
|
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;
|
fetch_length = 8;
|
||||||
command_flags = XHCI_TRB_BSR;
|
command_flags = XHCI_TRB_BSR;
|
||||||
}
|
}
|
||||||
|
@ -830,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);
|
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->params1 = ep_id << 27 | hub_flag << 26 | (slot_context->params1 & 0x00ffffff);
|
||||||
slot_context->num_ports = num_ports;
|
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);
|
xhci_ep_context_t *ep_context = (xhci_ep_context_t *)(ws->input_context_addr + (1 + ep_id) * ws->context_size);
|
||||||
ep_context->params1 = 0;
|
ep_context->params1 = 0;
|
||||||
|
@ -903,20 +890,6 @@ static void poll_keyboards(const usb_hcd_t *hcd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool set_heap_segment(void)
|
|
||||||
{
|
|
||||||
// Use the largest 32-bit addressable physical memory segment for the heap.
|
|
||||||
uintptr_t max_segment_size = 0;
|
|
||||||
for (int i = 0; i < pm_map_size && pm_map[i].end <= PAGE_C(4,GB); i++) {
|
|
||||||
uintptr_t segment_size = pm_map[i].end - pm_map[i].start;
|
|
||||||
if (segment_size >= max_segment_size) {
|
|
||||||
max_segment_size = segment_size;
|
|
||||||
heap_segment = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max_segment_size > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Driver Method Table
|
// Driver Method Table
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -937,17 +910,8 @@ static const hcd_methods_t methods = {
|
||||||
// Public Functions
|
// Public Functions
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
bool xhci_reset(uintptr_t base_addr)
|
||||||
{
|
{
|
||||||
if (heap_segment < 0) {
|
|
||||||
if (!set_heap_segment()) return false;
|
|
||||||
}
|
|
||||||
uintptr_t heap_segment_end = pm_map[heap_segment].end;
|
|
||||||
|
|
||||||
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;
|
xhci_cap_regs_t *cap_regs = (xhci_cap_regs_t *)base_addr;
|
||||||
|
|
||||||
#ifdef QEMU_WORKAROUND
|
#ifdef QEMU_WORKAROUND
|
||||||
|
@ -979,6 +943,44 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
timer--;
|
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) {
|
if (ext_cap->id == XHCI_EXT_CAP_SUPPORTED_PROTOCOL) {
|
||||||
xhci_supported_protocol_t *protocol = (xhci_supported_protocol_t *)ext_cap_base;
|
xhci_supported_protocol_t *protocol = (xhci_supported_protocol_t *)ext_cap_base;
|
||||||
|
|
||||||
|
@ -1016,14 +1018,12 @@ 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_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);
|
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.
|
// Record the heap states to allow us to free memory.
|
||||||
if (!halt_host_controller(op_regs)) return false;
|
uintptr_t initial_lm_heap_mark = heap_mark(HEAP_TYPE_LM_1);
|
||||||
|
uintptr_t initial_hm_heap_mark = heap_mark(HEAP_TYPE_HM_1);
|
||||||
if (!reset_host_controller(op_regs)) return false;
|
|
||||||
|
|
||||||
// Record the controller page size.
|
// Record the controller page size.
|
||||||
uintptr_t xhci_page_size = (read32(&op_regs->page_size) & 0xffff) << 12;
|
uintptr_t xhci_page_size = (read32(&op_regs->page_size) & 0xffff) << 12;
|
||||||
uintptr_t xhci_page_mask = xhci_page_size - 1;
|
|
||||||
|
|
||||||
// Find the maximum number of device slots the controller supports.
|
// Find the maximum number of device slots the controller supports.
|
||||||
int max_slots = cap_regs->hcs_params1 & 0xff;
|
int max_slots = cap_regs->hcs_params1 & 0xff;
|
||||||
|
@ -1033,31 +1033,30 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
| ((cap_regs->hcs_params2 >> 27) & 0x1f);
|
| ((cap_regs->hcs_params2 >> 27) & 0x1f);
|
||||||
|
|
||||||
// Allocate and clear the scratchpad memory on the heap. This must be aligned to the controller page size.
|
// Allocate and clear the scratchpad memory on the heap. This must be aligned to the controller page size.
|
||||||
// TODO: check for heap overflow.
|
|
||||||
uintptr_t scratchpad_size = num_scratchpad_buffers * xhci_page_size;
|
uintptr_t scratchpad_size = num_scratchpad_buffers * xhci_page_size;
|
||||||
pm_map[heap_segment].end -= num_pages(scratchpad_size);
|
uintptr_t scratchpad_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_size, xhci_page_size);
|
||||||
pm_map[heap_segment].end &= ~(xhci_page_mask >> PAGE_SHIFT);
|
if (scratchpad_paddr == 0) {
|
||||||
uintptr_t scratchpad_paddr = pm_map[heap_segment].end << PAGE_SHIFT;
|
goto no_keyboards_found;
|
||||||
|
}
|
||||||
uintptr_t scratchpad_vaddr = map_region(scratchpad_paddr, scratchpad_size, true);
|
uintptr_t scratchpad_vaddr = map_region(scratchpad_paddr, scratchpad_size, true);
|
||||||
if (scratchpad_vaddr == 0) {
|
if (scratchpad_vaddr == 0) {
|
||||||
pm_map[heap_segment].end = heap_segment_end;
|
goto no_keyboards_found;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset((void *)scratchpad_vaddr, 0, scratchpad_size);
|
memset((void *)scratchpad_vaddr, 0, scratchpad_size);
|
||||||
|
|
||||||
// Allocate and initialise the device context base address and scratchpad buffer arrays on the heap.
|
// Allocate and initialise the device context base address and scratchpad buffer arrays on the heap.
|
||||||
// Both need to be aligned on a 64 byte boundary.
|
// Both need to be aligned on a 64 byte boundary.
|
||||||
// TODO: check for heap overflow.
|
|
||||||
uintptr_t device_context_index_size = (1 + max_slots) * sizeof(uint64_t);
|
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_offs = round_up(device_context_index_size, 64);
|
||||||
uintptr_t scratchpad_buffer_index_size = num_scratchpad_buffers * sizeof(uint64_t);
|
uintptr_t scratchpad_buffer_index_size = num_scratchpad_buffers * sizeof(uint64_t);
|
||||||
pm_map[heap_segment].end -= num_pages(scratchpad_buffer_index_offs + scratchpad_buffer_index_size);
|
uintptr_t device_context_index_paddr = heap_alloc(HEAP_TYPE_HM_1, scratchpad_buffer_index_offs + scratchpad_buffer_index_size, 64);
|
||||||
uintptr_t device_context_index_paddr = pm_map[heap_segment].end << PAGE_SHIFT;
|
if (device_context_index_paddr == 0) {
|
||||||
|
goto no_keyboards_found;
|
||||||
|
}
|
||||||
uintptr_t device_context_index_vaddr = map_region(device_context_index_paddr, scratchpad_buffer_index_offs + scratchpad_buffer_index_size, true);
|
uintptr_t device_context_index_vaddr = map_region(device_context_index_paddr, scratchpad_buffer_index_offs + scratchpad_buffer_index_size, true);
|
||||||
if (device_context_index_vaddr == 0) {
|
if (device_context_index_vaddr == 0) {
|
||||||
pm_map[heap_segment].end = heap_segment_end;
|
goto no_keyboards_found;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset((void *)device_context_index_vaddr, 0, device_context_index_size);
|
memset((void *)device_context_index_vaddr, 0, device_context_index_size);
|
||||||
|
@ -1073,11 +1072,11 @@ 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,
|
// Allocate and initialise a workspace for this controller. This needs to be permanently mapped into virtual memory.
|
||||||
// so allocate it in the first segment.
|
uintptr_t workspace_addr = heap_alloc(HEAP_TYPE_LM_1, sizeof(workspace_t), PAGE_SIZE);
|
||||||
// TODO: check for segment overflow.
|
if (workspace_addr == 0) {
|
||||||
pm_map[0].end -= num_pages(sizeof(workspace_t));
|
goto no_keyboards_found;
|
||||||
uintptr_t workspace_addr = pm_map[0].end << PAGE_SHIFT;
|
}
|
||||||
workspace_t *ws = (workspace_t *)workspace_addr;
|
workspace_t *ws = (workspace_t *)workspace_addr;
|
||||||
|
|
||||||
memset(ws, 0, sizeof(workspace_t));
|
memset(ws, 0, sizeof(workspace_t));
|
||||||
|
@ -1093,6 +1092,14 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
ws->cr_enqueue_state = WS_CR_SIZE; // cycle = 1, index = 0
|
ws->cr_enqueue_state = WS_CR_SIZE; // cycle = 1, index = 0
|
||||||
ws->er_dequeue_state = WS_ER_SIZE; // cycle = 1, index = 0
|
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 = heap_alloc(HEAP_TYPE_LM_1, XHCI_MAX_IP_CONTEXT_SIZE, PAGE_SIZE);
|
||||||
|
if (ws->input_context_addr == 0) {
|
||||||
|
goto no_keyboards_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((void *)ws->input_context_addr, 0, XHCI_MAX_IP_CONTEXT_SIZE);
|
||||||
|
|
||||||
// Initialise the driver object for this controller.
|
// Initialise the driver object for this controller.
|
||||||
hcd->methods = &methods;
|
hcd->methods = &methods;
|
||||||
hcd->ws = &ws->base_ws;
|
hcd->ws = &ws->base_ws;
|
||||||
|
@ -1110,18 +1117,14 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
write64(&op_regs->dcbaap, device_context_index_paddr);
|
write64(&op_regs->dcbaap, device_context_index_paddr);
|
||||||
write32(&op_regs->config, (read32(&op_regs->config) & 0xfffffc00) | max_slots);
|
write32(&op_regs->config, (read32(&op_regs->config) & 0xfffffc00) | max_slots);
|
||||||
if (!start_host_controller(op_regs)) {
|
if (!start_host_controller(op_regs)) {
|
||||||
pm_map[0].end += num_pages(sizeof(workspace_t));
|
goto no_keyboards_found;
|
||||||
pm_map[heap_segment].end = heap_segment_end;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a hub descriptor for the root hub.
|
// Construct a hub descriptor for the root hub.
|
||||||
usb_hub_t root_hub;
|
usb_hub_t root_hub;
|
||||||
|
memset(&root_hub, 0, sizeof(root_hub));
|
||||||
root_hub.ep0 = NULL;
|
root_hub.ep0 = NULL;
|
||||||
root_hub.level = 0;
|
|
||||||
root_hub.route = 0;
|
|
||||||
root_hub.num_ports = cap_regs->hcs_params1 & 0xff;
|
root_hub.num_ports = cap_regs->hcs_params1 & 0xff;
|
||||||
root_hub.power_up_delay = 0;
|
|
||||||
|
|
||||||
usleep(100*MILLISEC); // USB maximum device attach time.
|
usleep(100*MILLISEC); // USB maximum device attach time.
|
||||||
|
|
||||||
|
@ -1177,16 +1180,8 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
num_keyboards, num_keyboards != 1 ? "s" : "");
|
num_keyboards, num_keyboards != 1 ? "s" : "");
|
||||||
|
|
||||||
if (num_keyboards == 0) {
|
if (num_keyboards == 0) {
|
||||||
// Halt the host controller.
|
|
||||||
(void)halt_host_controller(op_regs);
|
(void)halt_host_controller(op_regs);
|
||||||
|
goto no_keyboards_found;
|
||||||
// Free the pages we allocated in segment 0.
|
|
||||||
pm_map[0].end += num_pages(sizeof(workspace_t));
|
|
||||||
|
|
||||||
// Free the pages we allocated in the heap segment.
|
|
||||||
pm_map[heap_segment].end = heap_segment_end;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise the interrupt TRB ring for each keyboard interface.
|
// Initialise the interrupt TRB ring for each keyboard interface.
|
||||||
|
@ -1200,4 +1195,9 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
no_keyboards_found:
|
||||||
|
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"
|
#include "usbhcd.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises the XHCI device found at base_addr, scans all the attached USB
|
* If necessary, takes ownership of the XHCI device at the specified base
|
||||||
* devices, and configures any HID USB keyboard devices it finds to generate
|
* address, then resets it.
|
||||||
* periodic interrupt transfers that report key presses. Initialises hcd and
|
*
|
||||||
* returns true if the device was successfully initialised and one or more
|
* \param base_addr - the base address of the device in virtual memory
|
||||||
* keyboards were found.
|
*
|
||||||
|
* \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
|
#endif // XHCI_H
|
||||||
|
|
|
@ -70,7 +70,7 @@ int test_addr_walk1(int my_cpu)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
write_word(p2, ~invert ^ (testword_t)p2);
|
write_word(p2, ~invert ^ (testword_t)p2);
|
||||||
|
|
||||||
testword_t actual = read_word(p1);
|
testword_t actual = read_word(p1);
|
||||||
if (unlikely(actual != expect)) {
|
if (unlikely(actual != expect)) {
|
||||||
addr_error(p1, p2, expect, actual);
|
addr_error(p1, p2, expect, actual);
|
||||||
|
|
|
@ -39,6 +39,7 @@ int test_block_move(int my_cpu, int iterations)
|
||||||
for (int i = 0; i < vm_map_size; i++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = start;
|
testword_t *pe = start;
|
||||||
|
@ -84,11 +85,12 @@ int test_block_move(int my_cpu, int iterations)
|
||||||
}
|
}
|
||||||
flush_caches(my_cpu);
|
flush_caches(my_cpu);
|
||||||
|
|
||||||
// Now move the data around. First move the data up half of the segment size
|
// Now move the data around. First move the data up half of the segment size
|
||||||
// we are testing. Then move the data to the original location + 32 bytes.
|
// we are testing. Then move the data to the original location + 32 bytes.
|
||||||
for (int i = 0; i < vm_map_size; i++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, 16 * sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
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
|
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
|
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++) {
|
for (int j = 0; j < vm_map_size; j++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
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;
|
int k = 0;
|
||||||
testword_t *p = start;
|
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++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
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
|
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
|
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++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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++) {
|
for (int j = 0; j < vm_map_size; j++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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--) {
|
for (int j = vm_map_size - 1; j >= 0; j--) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
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 *p = end;
|
||||||
testword_t *ps = 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++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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++) {
|
for (int j = 0; j < vm_map_size; j++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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++) {
|
for (int i = 0; i < vm_map_size; i++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, i, sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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++) {
|
for (int j = 0; j < vm_map_size; j++) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
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 *p = start;
|
||||||
testword_t *pe = 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--) {
|
for (int j = vm_map_size - 1; j >= 0; j--) {
|
||||||
testword_t *start, *end;
|
testword_t *start, *end;
|
||||||
calculate_chunk(&start, &end, my_cpu, j, sizeof(testword_t));
|
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 *p = end;
|
||||||
testword_t *ps = end;
|
testword_t *ps = end;
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "vmem.h"
|
||||||
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
@ -127,12 +129,20 @@ int test_own_addr1(int my_cpu)
|
||||||
|
|
||||||
int test_own_addr2(int my_cpu, int stage)
|
int test_own_addr2(int my_cpu, int stage)
|
||||||
{
|
{
|
||||||
static testword_t offset = 0;
|
|
||||||
static int last_stage = -1;
|
|
||||||
|
|
||||||
int ticks = 0;
|
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) {
|
switch (stage) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -145,6 +155,5 @@ int test_own_addr2(int my_cpu, int stage)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_stage = stage;
|
|
||||||
return ticks;
|
return ticks;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
test_pattern_t test_list[NUM_TEST_PATTERNS] = {
|
test_pattern_t test_list[NUM_TEST_PATTERNS] = {
|
||||||
// ena, cpu, stgs, itrs, errs, description
|
// ena, cpu, stgs, itrs, errs, description
|
||||||
{ true, SEQ, 1, 6, 0, "[Address test, walking ones, no cache] "},
|
{ 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, SEQ, 2, 6, 0, "[Address test, own address + window] "},
|
||||||
{ true, PAR, 1, 6, 0, "[Moving inversions, 1s & 0s] "},
|
{ true, PAR, 1, 6, 0, "[Moving inversions, 1s & 0s] "},
|
||||||
{ true, PAR, 1, 3, 0, "[Moving inversions, 8 bit pattern] "},
|
{ true, PAR, 1, 3, 0, "[Moving inversions, 8 bit pattern] "},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue