mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
Compare commits
197 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cb95b5b378 | |||
| 40b5112440 | |||
| 27ecc36c0b | |||
| 59f27d6935 | |||
| 165995b7e9 | |||
| b940d54235 | |||
| b66f6025fa | |||
| b52b4a46d9 | |||
| 764e34f15a | |||
| afae881782 | |||
| 43deab89c3 | |||
| 19f39bc07a | |||
| f39b48d5f8 | |||
| 37850e0e85 | |||
| 9bbe77669c | |||
| 170bbfd487 | |||
| dcad73ca5a | |||
| da5188f3ea | |||
| ca483a196c | |||
| a15ce00182 | |||
| 390bce9516 | |||
| 1a84facf12 | |||
| 88c2a01e1a | |||
| 926816c58f | |||
| c11734eee0 | |||
| fa4bda617d | |||
| bac967d51a | |||
| 17882e76af | |||
| 1344e13a03 | |||
| a67f913d66 | |||
| 89bb926a04 | |||
| 1ab4d3079d | |||
| df2f23e333 | |||
| 226531ed36 | |||
| 06e229590c | |||
| 24a855f1fc | |||
| 62b6d36335 | |||
| cea22d76e4 | |||
| c4471e3408 | |||
| 636ccb4ca5 | |||
| b1c13cc43e | |||
| 8da22a59ee | |||
| 37edfea72b | |||
| eb720d2224 | |||
| 75c7904482 | |||
| 1b23d4de25 | |||
| 7cd73884e5 | |||
| 0eb8fbd0bf | |||
| da7b266289 | |||
| 182ee90931 | |||
| 43e385091a | |||
| 25ffcd79bf | |||
| 834f319f87 | |||
| ee6185dcf5 | |||
| e5f3ba0ca7 | |||
| 582132fe3f | |||
| 075292cc2d | |||
| 929f06a76d | |||
| 943d75b557 | |||
| 3e721e0c08 | |||
| e10dfe5dc7 | |||
| 88b291d647 | |||
| 94b39fbe92 | |||
| 0f5abd8b11 | |||
| a846c4ccfc | |||
| e7ae51b0d7 | |||
| af4583b214 | |||
| 36a27b22b1 | |||
| 0cc0f47443 | |||
| 65d69d33da | |||
| 963ec1c4f3 | |||
| 8f6a9399b3 | |||
| a881a26061 | |||
| b234226dbc | |||
| 8e2469c861 | |||
| 989dbe0bc4 | |||
| 6f70e8be83 | |||
| 17135c83fb | |||
| 27398f1360 | |||
| de8a0821c7 | |||
| 2eea04c02c | |||
| 908174ec7e | |||
| bac13ba1f6 | |||
| 13e390d54e | |||
| 26d3ef062b | |||
| 4b7d9a6af0 | |||
| 6d29415c89 | |||
| 6ca597eee9 | |||
| e66552eeed | |||
| 08fcb0e8fb | |||
| c6226f104e | |||
| 0abb3e85e5 | |||
| 4ed7a5718f | |||
| fa62213231 | |||
| 119c415ee4 | |||
| 9e92c39894 | |||
| 3fc1b407d2 | |||
| 0958e01463 | |||
| 337880deaa | |||
| f22879ca99 | |||
| 98dd25a3bb | |||
| a147245f1a | |||
| c3dd3168c9 | |||
| b829b1750d | |||
| 03ff1bb99a | |||
| 18582a05fc | |||
| 6714b20ea2 | |||
| b37d89db90 | |||
| cc858acd32 | |||
| b30a0987e2 | |||
| 3d8a614657 | |||
| a9e89787d0 | |||
| 678a60f61d | |||
| 8c8ead2530 | |||
| 77b07ea4fd | |||
| d8f9c221ed | |||
| 595b1796f6 | |||
| 1bd01b761f | |||
| 5524bb9832 | |||
| 36e1a559a2 | |||
| 1f3a37e342 | |||
| 74ec00a9f3 | |||
| f883203132 | |||
| 115707c0ed | |||
| ff0f860483 | |||
| 8b14652e50 | |||
| 56cc61a168 | |||
| cac3a584dc | |||
| 8cbf248198 | |||
| 8b1d34badf | |||
| cc1e27e525 | |||
| ae4e85bde9 | |||
| eeb7cd56e5 | |||
| 0aa2e4ec96 | |||
| 9e99a55b31 | |||
| c1834f323f | |||
| d5c08f78bd | |||
| c30b71ee9c | |||
| f3036fc213 | |||
| 59d065c9ac | |||
| 48ae5d5361 | |||
| 6701d91c50 | |||
| b5b60ea33d | |||
| 8244410690 | |||
| daa9e54ab8 | |||
| 3ef4f7e2ef | |||
| cc07ed7c7e | |||
| 6f57d91935 | |||
| e17568ad06 | |||
| 2524a60550 | |||
| 280942a92a | |||
| 6d98e0ca47 | |||
| 0c67a3632d | |||
| c57887bfc8 | |||
| 18af669701 | |||
| cfe65aa826 | |||
| ae435cb4cc | |||
| f8a0d1c0b8 | |||
| f0b1025503 | |||
| c832580f19 | |||
| 9a118322a0 | |||
| 2689a6e776 | |||
| 4fa4052c7e | |||
| 25a3d3acab | |||
| 8ab9bdca4f | |||
| 12776acce5 | |||
| 367e022b5e | |||
| b9a60fb0b7 | |||
| a64764d10f | |||
| bc75bbaf17 | |||
| e7adf5701f | |||
| 92ab2de3a4 | |||
| 3184ff74eb | |||
| 9cb0a4b8ec | |||
| b0093571f8 | |||
| 6a7f560e60 | |||
| 5b43181436 | |||
| d2e1601cf4 | |||
| 95b8338f0d | |||
| 28184b7c22 | |||
| 3c214f0465 | |||
| ce2200d5fb | |||
| c4a8d90387 | |||
| 79d85e29aa | |||
| d27cd8196d | |||
| 03eea19c19 | |||
| 0bb0aea878 | |||
| f9beb20e99 | |||
| f93e6b712f | |||
| 22cc65535a | |||
| bd13697446 | |||
| 9fb28080d9 | |||
| 1e4c3789e9 | |||
| 0d04635ef0 | |||
| 1d1cf74a5e | |||
| aa368ba529 | |||
| 2c6a15d2a3 |
17
.github/workflows/build.yml
vendored
17
.github/workflows/build.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@ -32,14 +32,14 @@ jobs:
|
||||
needs: cache
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Cache permissions
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@ -49,7 +49,8 @@ jobs:
|
||||
sudo apt update
|
||||
sudo apt install -y -o Acquire::Retries=50 \
|
||||
mtools syslinux isolinux \
|
||||
libc6-dev-i386 libc6-dbg:i386 valgrind
|
||||
libc6-dev-i386 valgrind \
|
||||
libgcc-s1:i386 libc6-dbg:i386
|
||||
- name: Build (BIOS)
|
||||
run: |
|
||||
make -j 4 -C src
|
||||
@ -67,14 +68,14 @@ jobs:
|
||||
needs: cache
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Cache permissions
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
@ -96,14 +97,14 @@ jobs:
|
||||
needs: cache
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Cache permissions
|
||||
run: |
|
||||
sudo chown $(id -un) /var/cache/apt/archives
|
||||
- name: Cache packages
|
||||
uses: actions/cache/restore@v3
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: /var/cache/apt/archives/*.deb
|
||||
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
|
||||
2
.github/workflows/coverity.yml
vendored
2
.github/workflows/coverity.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Download Coverity Scan
|
||||
run: |
|
||||
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \
|
||||
|
||||
@ -46,11 +46,19 @@ def create_snapshot(region, description, image):
|
||||
return snapshot_id
|
||||
|
||||
|
||||
def import_image(region, name, architecture, image, public):
|
||||
def import_image(region, name, architecture, image, public, overwrite):
|
||||
"""Import an AMI image"""
|
||||
client = boto3.client('ec2', region_name=region)
|
||||
resource = boto3.resource('ec2', region_name=region)
|
||||
description = '%s (%s)' % (name, architecture)
|
||||
images = client.describe_images(Filters=[{'Name': 'name',
|
||||
'Values': [description]}])
|
||||
if overwrite and images['Images']:
|
||||
images = images['Images'][0]
|
||||
image_id = images['ImageId']
|
||||
snapshot_id = images['BlockDeviceMappings'][0]['Ebs']['SnapshotId']
|
||||
resource.Image(image_id).deregister()
|
||||
resource.Snapshot(snapshot_id).delete()
|
||||
snapshot_id = create_snapshot(region=region, description=description,
|
||||
image=image)
|
||||
client.get_waiter('snapshot_completed').wait(SnapshotIds=[snapshot_id])
|
||||
@ -88,6 +96,8 @@ parser.add_argument('--name', '-n',
|
||||
help="Image name")
|
||||
parser.add_argument('--public', '-p', action='store_true',
|
||||
help="Make image public")
|
||||
parser.add_argument('--overwrite', action='store_true',
|
||||
help="Overwrite any existing image with same name")
|
||||
parser.add_argument('--region', '-r', action='append',
|
||||
help="AWS region(s)")
|
||||
parser.add_argument('--wiki', '-w', metavar='FILE',
|
||||
@ -115,7 +125,8 @@ with ThreadPoolExecutor(max_workers=len(imports)) as executor:
|
||||
name=args.name,
|
||||
architecture=architectures[image],
|
||||
image=image,
|
||||
public=args.public): (region, image)
|
||||
public=args.public,
|
||||
overwrite=args.overwrite): (region, image)
|
||||
for region, image in imports}
|
||||
results = {futures[future]: future.result()
|
||||
for future in as_completed(futures)}
|
||||
|
||||
68
contrib/cloud/aws-int13con
Executable file
68
contrib/cloud/aws-int13con
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
import boto3
|
||||
|
||||
BLOCKSIZE = 512 * 1024
|
||||
|
||||
IPXELOG_OFFSET = 16 * 1024
|
||||
|
||||
IPXELOG_MAGIC = b'iPXE LOG'
|
||||
|
||||
|
||||
def create_snapshot(region, instance_id):
|
||||
"""Create root volume snapshot"""
|
||||
client = boto3.client('ec2', region_name=region)
|
||||
resource = boto3.resource('ec2', region_name=region)
|
||||
instance = resource.Instance(instance_id)
|
||||
volumes = list(instance.volumes.all())
|
||||
snapshot = volumes[0].create_snapshot()
|
||||
snapshot.wait_until_completed()
|
||||
return snapshot.id
|
||||
|
||||
|
||||
def get_snapshot_block(region, snapshot_id, index):
|
||||
"""Get block content from snapshot"""
|
||||
client = boto3.client('ebs', region_name=region)
|
||||
blocks = client.list_snapshot_blocks(SnapshotId=snapshot_id,
|
||||
StartingBlockIndex=index)
|
||||
token = blocks['Blocks'][0]['BlockToken']
|
||||
block = client.get_snapshot_block(SnapshotId=snapshot_id,
|
||||
BlockIndex=index,
|
||||
BlockToken=token)
|
||||
return block['BlockData'].read()
|
||||
|
||||
|
||||
def get_block0_content(region, instance_id):
|
||||
"""Get content of root volume block zero from instance"""
|
||||
client = boto3.client('ec2', region_name=region)
|
||||
resource = boto3.resource('ec2', region_name=region)
|
||||
snapshot_id = create_snapshot(region, instance_id)
|
||||
block = get_snapshot_block(region, snapshot_id, 0)
|
||||
resource.Snapshot(snapshot_id).delete()
|
||||
return block
|
||||
|
||||
|
||||
def get_int13con_output(region, instance_id):
|
||||
"""Get INT13 console output"""
|
||||
block = get_block0_content(region, instance_id)
|
||||
logpart = block[IPXELOG_OFFSET:]
|
||||
magic = logpart[:len(IPXELOG_MAGIC)]
|
||||
if magic != IPXELOG_MAGIC:
|
||||
raise ValueError("Invalid log magic signature")
|
||||
log = logpart[len(IPXELOG_MAGIC):].split(b'\0')[0]
|
||||
return log.decode()
|
||||
|
||||
|
||||
# Parse command-line arguments
|
||||
parser = argparse.ArgumentParser(description="Get AWS INT13 console output")
|
||||
parser.add_argument('--region', '-r', help="AWS region")
|
||||
parser.add_argument('id', help="Instance ID")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Get console output from INT13CON partition
|
||||
output = get_int13con_output(args.region, args.id)
|
||||
|
||||
# Print console output
|
||||
print(output)
|
||||
2
src/.gitignore
vendored
2
src/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
.toolcheck
|
||||
.echocheck
|
||||
TAGS*
|
||||
bin*
|
||||
bin-*
|
||||
|
||||
@ -23,9 +23,9 @@ NON_AUTO_MEDIA += efidrv
|
||||
NON_AUTO_MEDIA += drv.efi
|
||||
NON_AUTO_MEDIA += efirom
|
||||
|
||||
# Include SNP driver in the all-drivers build
|
||||
# Include SNP and MNP drivers in the all-drivers build
|
||||
#
|
||||
DRIVERS_net += snp
|
||||
DRIVERS_net += snp mnp
|
||||
|
||||
# Rules for building EFI files
|
||||
#
|
||||
@ -50,6 +50,10 @@ $(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
|
||||
$(QM)$(ECHO) " [CAB] $@"
|
||||
$(Q)$(LCAB) -n -q $(ALL_drv.efi) $@
|
||||
|
||||
$(BIN)/%.iso $(BIN)/%.usb : $(BIN)/%.efi util/genfsimg
|
||||
$(BIN)/%.iso : $(BIN)/%.efi util/genfsimg
|
||||
$(QM)$(ECHO) " [GENFSIMG] $@"
|
||||
$(Q)util/genfsimg -o $@ $<
|
||||
|
||||
$(BIN)/%.usb : $(BIN)/%.efi util/genfsimg
|
||||
$(QM)$(ECHO) " [GENFSIMG] $@"
|
||||
$(Q)util/genfsimg -o $@ $<
|
||||
|
||||
@ -502,6 +502,13 @@ LDFLAGS += --gc-sections
|
||||
#
|
||||
LDFLAGS += -static
|
||||
|
||||
# Use separate code segment if supported by linker
|
||||
#
|
||||
ZSC_TEST = $(LD) -z separate-code --version 2>&1 > /dev/null
|
||||
ZSC_FLAGS := $(shell [ -z "`$(ZSC_TEST)`" ] && \
|
||||
$(ECHO) '-z separate-code -z max-page-size=4096')
|
||||
LDFLAGS += $(ZSC_FLAGS)
|
||||
|
||||
# compiler.h is needed for our linking and debugging system
|
||||
#
|
||||
CFLAGS += -include include/compiler.h
|
||||
@ -1002,6 +1009,7 @@ endif
|
||||
# Device ID tables (using IDs from ROM definition file)
|
||||
#
|
||||
define obj_pci_id_asm
|
||||
.section ".note.GNU-stack", "", $(ASM_TCHAR)progbits
|
||||
.section ".pci_devlist.$(1)", "a", $(ASM_TCHAR)progbits
|
||||
.globl pci_devlist_$(1)
|
||||
pci_devlist_$(1):
|
||||
@ -1171,7 +1179,7 @@ BLIB = $(BIN)/blib.a
|
||||
$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
|
||||
$(Q)$(RM) $(BLIB)
|
||||
$(QM)$(ECHO) " [AR] $@"
|
||||
$(Q)$(AR) rD $@ $(sort $(BLIB_OBJS))
|
||||
$(Q)$(AR) rcD $@ $(sort $(BLIB_OBJS))
|
||||
$(Q)$(OBJCOPY) --enable-deterministic-archives \
|
||||
--prefix-symbols=$(SYMBOL_PREFIX) $@
|
||||
$(Q)$(RANLIB) -D $@
|
||||
|
||||
@ -9,4 +9,5 @@ INCDIRS += arch/arm/include
|
||||
|
||||
# ARM-specific directories containing source files
|
||||
#
|
||||
SRCDIRS += arch/arm/core
|
||||
SRCDIRS += arch/arm/interface/efi
|
||||
|
||||
@ -46,7 +46,7 @@ union arm32_io_qword {
|
||||
*
|
||||
* This is not atomic for ARM32.
|
||||
*/
|
||||
static uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
|
||||
static __unused uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
|
||||
volatile union arm32_io_qword *ptr =
|
||||
container_of ( io_addr, union arm32_io_qword, qword );
|
||||
union arm32_io_qword tmp;
|
||||
@ -64,7 +64,8 @@ static uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
|
||||
*
|
||||
* This is not atomic for ARM32.
|
||||
*/
|
||||
static void arm32_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
|
||||
static __unused void arm32_writeq ( uint64_t data,
|
||||
volatile uint64_t *io_addr ) {
|
||||
volatile union arm32_io_qword *ptr =
|
||||
container_of ( io_addr, union arm32_io_qword, qword );
|
||||
union arm32_io_qword tmp;
|
||||
@ -82,7 +83,6 @@ PROVIDE_IOAPI_INLINE ( arm, readl );
|
||||
PROVIDE_IOAPI_INLINE ( arm, writeb );
|
||||
PROVIDE_IOAPI_INLINE ( arm, writew );
|
||||
PROVIDE_IOAPI_INLINE ( arm, writel );
|
||||
PROVIDE_IOAPI_INLINE ( arm, iodelay );
|
||||
PROVIDE_IOAPI_INLINE ( arm, mb );
|
||||
#ifdef __aarch64__
|
||||
PROVIDE_IOAPI_INLINE ( arm, readq );
|
||||
@ -91,3 +91,4 @@ PROVIDE_IOAPI_INLINE ( arm, writeq );
|
||||
PROVIDE_IOAPI ( arm, readq, arm32_readq );
|
||||
PROVIDE_IOAPI ( arm, writeq, arm32_writeq );
|
||||
#endif
|
||||
PROVIDE_DUMMY_PIO ( arm );
|
||||
|
||||
12
src/arch/arm/include/bits/mp.h
Normal file
12
src/arch/arm/include/bits/mp.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_MP_H
|
||||
#define _BITS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ARM-specific multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_MP_H */
|
||||
@ -9,6 +9,4 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
|
||||
#endif /* _BITS_PCI_IO_H */
|
||||
|
||||
@ -15,6 +15,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define IOAPI_PREFIX_arm __arm_
|
||||
#endif
|
||||
|
||||
#include <ipxe/dummy_pio.h>
|
||||
|
||||
/*
|
||||
* Memory space mappings
|
||||
*
|
||||
@ -77,55 +79,6 @@ ARM_WRITEX ( w, uint16_t, "h", "" );
|
||||
ARM_WRITEX ( l, uint32_t, "", "" );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy PIO reads and writes up to 32 bits
|
||||
*
|
||||
* There is no common standard for I/O-space access for ARM, and
|
||||
* non-MMIO peripherals are vanishingly rare. Provide dummy
|
||||
* implementations that will allow code to link and should cause
|
||||
* drivers to simply fail to detect hardware at runtime.
|
||||
*
|
||||
*/
|
||||
|
||||
#define ARM_INX( _suffix, _type ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( arm, in ## _suffix ) ( volatile _type *io_addr __unused) { \
|
||||
return ~( (_type) 0 ); \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( arm, ins ## _suffix ) ( volatile _type *io_addr __unused, \
|
||||
_type *data, unsigned int count ) { \
|
||||
memset ( data, 0xff, count * sizeof ( *data ) ); \
|
||||
}
|
||||
ARM_INX ( b, uint8_t );
|
||||
ARM_INX ( w, uint16_t );
|
||||
ARM_INX ( l, uint32_t );
|
||||
|
||||
#define ARM_OUTX( _suffix, _type ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( arm, out ## _suffix ) ( _type data __unused, \
|
||||
volatile _type *io_addr __unused ) { \
|
||||
/* Do nothing */ \
|
||||
} \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( arm, outs ## _suffix ) ( volatile _type *io_addr __unused, \
|
||||
const _type *data __unused, \
|
||||
unsigned int count __unused ) { \
|
||||
/* Do nothing */ \
|
||||
}
|
||||
ARM_OUTX ( b, uint8_t );
|
||||
ARM_OUTX ( w, uint16_t );
|
||||
ARM_OUTX ( l, uint32_t );
|
||||
|
||||
/*
|
||||
* Slow down I/O
|
||||
*
|
||||
*/
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( arm, iodelay ) ( void ) {
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory barrier
|
||||
*
|
||||
@ -140,4 +93,7 @@ IOAPI_INLINE ( arm, mb ) ( void ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Dummy PIO */
|
||||
DUMMY_PIO ( arm );
|
||||
|
||||
#endif /* _IPXE_ARM_IO_H */
|
||||
|
||||
@ -46,8 +46,12 @@ static void efiarm_cpu_nap ( void ) {
|
||||
* The EFI shell doesn't seem to bother sleeping the CPU; it
|
||||
* just sits there idly burning power.
|
||||
*
|
||||
* If a shutdown is in progess, there may be nothing to
|
||||
* generate an interrupt since the timer is disabled in the
|
||||
* first step of ExitBootServices().
|
||||
*/
|
||||
__asm__ __volatile__ ( "wfi" );
|
||||
if ( ! efi_shutdown_in_progress )
|
||||
__asm__ __volatile__ ( "wfi" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efiarm, cpu_nap, efiarm_cpu_nap );
|
||||
|
||||
@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint32_t multiplicand_element;
|
||||
@ -62,9 +66,9 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -73,7 +77,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t"
|
||||
"ldr %3, [%0]\n\t"
|
||||
|
||||
@ -310,7 +310,9 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
.thumb
|
||||
|
||||
/**
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
.arm
|
||||
|
||||
/**
|
||||
|
||||
@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint64_t multiplicand_element;
|
||||
@ -63,9 +67,9 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -74,7 +78,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mul %1, %6, %7\n\t"
|
||||
"umulh %2, %6, %7\n\t"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
|
||||
/* Must match jmp_buf structure layout */
|
||||
|
||||
@ -311,7 +311,9 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
* Interrupt handlers
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.section ".text", "ax", @progbits
|
||||
.code32
|
||||
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code32
|
||||
.arch i386
|
||||
|
||||
/* Must match jmp_buf structure layout */
|
||||
.struct 0
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code32
|
||||
.arch i386
|
||||
|
||||
.section ".data", "aw", @progbits
|
||||
|
||||
@ -20,6 +20,7 @@ CFLAGS += -fshort-wchar
|
||||
|
||||
# LoongArch64-specific directories containing source files
|
||||
SRCDIRS += arch/loong64/core
|
||||
SRCDIRS += arch/loong64/interface/efi
|
||||
|
||||
# Include platform-specific Makefile
|
||||
MAKEDEPS += arch/loong64/Makefile.$(PLATFORM)
|
||||
|
||||
14
src/arch/loong64/Makefile.efi
Normal file
14
src/arch/loong64/Makefile.efi
Normal file
@ -0,0 +1,14 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# Specify EFI image builder
|
||||
#
|
||||
ELF2EFI = $(ELF2EFI64)
|
||||
|
||||
# Specify EFI boot file
|
||||
#
|
||||
EFI_BOOT_FILE = bootloongarch64.efi
|
||||
|
||||
# Include generic EFI Makefile
|
||||
#
|
||||
MAKEDEPS += Makefile.efi
|
||||
include Makefile.efi
|
||||
@ -37,19 +37,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint64_t multiplicand_element;
|
||||
@ -64,9 +68,9 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -75,7 +79,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mul.d %1, %6, %7\n\t"
|
||||
"mulh.du %2, %6, %7\n\t"
|
||||
|
||||
46
src/arch/loong64/core/loong64_io.c
Normal file
46
src/arch/loong64/core/loong64_io.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/loong64_io.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE I/O API for LoongArch64
|
||||
*
|
||||
*/
|
||||
|
||||
PROVIDE_IOAPI_INLINE ( loong64, phys_to_bus );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, bus_to_phys );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, readb );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, readw );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, readl );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, readq );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, writeb );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, writew );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, writel );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, writeq );
|
||||
PROVIDE_IOAPI_INLINE ( loong64, mb );
|
||||
PROVIDE_DUMMY_PIO ( loong64 );
|
||||
@ -53,34 +53,37 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_addend_i;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
__asm__ __volatile__ ( "move $t0, $zero\n"
|
||||
"1:\n\t"
|
||||
"ld.d %3, %0, 0\n\t"
|
||||
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load addend[i] and value[i] */
|
||||
"ld.d %3, %0, 0\n\t"
|
||||
"ld.d %4, %1, 0\n\t"
|
||||
/* Add carry flag and addend */
|
||||
"add.d %4, %4, %5\n\t"
|
||||
"sltu %6, %4, %5\n\t"
|
||||
"add.d %4, %4, %3\n\t"
|
||||
"sltu %5, %4, %3\n\t"
|
||||
"or %5, %5, %6\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %4, %1, 0\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, 8\n\t"
|
||||
"ld.d %4, %1, 0\n\t"
|
||||
|
||||
"add.d %4, %4, $t0\n\t"
|
||||
"sltu $t0, %4, $t0\n\t"
|
||||
|
||||
"add.d %4, %4, %3\n\t"
|
||||
"sltu $t1, %4, %3\n\t"
|
||||
|
||||
"or $t0, $t0, $t1\n\t"
|
||||
"st.d %4, %1, 0\n\t"
|
||||
"addi.d %1, %1, 8\n\t"
|
||||
"addi.w %2, %2, -1\n\t"
|
||||
"bnez %2, 1b"
|
||||
"bnez %2, 1b\n\t"
|
||||
: "=r" ( discard_addend ),
|
||||
"=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_addend_i ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( addend0 ),
|
||||
"1" ( value0 ),
|
||||
"2" ( size )
|
||||
: "t0", "t1" );
|
||||
: "0" ( addend0 ), "1" ( value0 ),
|
||||
"2" ( size ), "5" ( 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,35 +96,43 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0,
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_subtrahend;
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_subtrahend_i;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
unsigned int flag = 0;
|
||||
|
||||
discard_subtrahend = (uint64_t*) subtrahend0;
|
||||
discard_value = value0;
|
||||
discard_size = size;
|
||||
|
||||
do {
|
||||
discard_subtrahend_i = *discard_subtrahend;
|
||||
discard_subtrahend++;
|
||||
discard_value_i = *discard_value;
|
||||
|
||||
discard_value_i = discard_value_i - discard_subtrahend_i - flag;
|
||||
|
||||
if ( *discard_value < (discard_subtrahend_i + flag)) {
|
||||
flag = 1;
|
||||
} else {
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
*discard_value = discard_value_i;
|
||||
|
||||
discard_value++;
|
||||
discard_size -= 1;
|
||||
} while (discard_size != 0);
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load subtrahend[i] and value[i] */
|
||||
"ld.d %3, %0, 0\n\t"
|
||||
"ld.d %4, %1, 0\n\t"
|
||||
/* Subtract carry flag and subtrahend */
|
||||
"sltu %6, %4, %5\n\t"
|
||||
"sub.d %4, %4, %5\n\t"
|
||||
"sltu %5, %4, %3\n\t"
|
||||
"sub.d %4, %4, %3\n\t"
|
||||
"or %5, %5, %6\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %4, %1, 0\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, 8\n\t"
|
||||
"addi.d %1, %1, 8\n\t"
|
||||
"addi.w %2, %2, -1\n\t"
|
||||
"bnez %2, 1b\n\t"
|
||||
: "=r" ( discard_subtrahend ),
|
||||
"=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_subtrahend_i ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( subtrahend0 ), "1" ( value0 ),
|
||||
"2" ( size ), "5" ( 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,30 +143,37 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0,
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
uint64_t current_value_i;
|
||||
unsigned int flag = 0;
|
||||
|
||||
discard_value = value0;
|
||||
discard_size = size;
|
||||
do {
|
||||
discard_value_i = *discard_value;
|
||||
current_value_i = discard_value_i;
|
||||
|
||||
discard_value_i += discard_value_i + flag;
|
||||
|
||||
if (discard_value_i < current_value_i) {
|
||||
flag = 1;
|
||||
} else {
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
*discard_value = discard_value_i;
|
||||
discard_value++;
|
||||
discard_size -= 1;
|
||||
} while ( discard_size != 0 );
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load value[i] */
|
||||
"ld.d %2, %0, 0\n\t"
|
||||
/* Shift left */
|
||||
"rotri.d %2, %2, 63\n\t"
|
||||
"andi %4, %2, 1\n\t"
|
||||
"xor %2, %2, %4\n\t"
|
||||
"or %2, %2, %3\n\t"
|
||||
"move %3, %4\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %2, %0, 0\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, 8\n\t"
|
||||
"addi.w %1, %1, -1\n\t"
|
||||
"bnez %1, 1b\n\t"
|
||||
: "=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 ), "1" ( size ), "3" ( 0 )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,27 +184,37 @@ bigint_rol_raw ( uint64_t *value0, unsigned int size ) {
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_ror_raw ( uint64_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
uint64_t *discard_value;
|
||||
uint64_t discard_value_i;
|
||||
uint64_t discard_value_j;
|
||||
uint64_t discard_carry;
|
||||
uint64_t discard_temp;
|
||||
unsigned int discard_size;
|
||||
|
||||
discard_value = value0;
|
||||
discard_size = size;
|
||||
|
||||
discard_value_j = 0;
|
||||
|
||||
do {
|
||||
discard_size -= 1;
|
||||
|
||||
discard_value_i = *(discard_value + discard_size);
|
||||
|
||||
discard_value_j = (discard_value_j << 63) | (discard_value_i >> 1);
|
||||
|
||||
*(discard_value + discard_size) = discard_value_j;
|
||||
|
||||
discard_value_j = discard_value_i;
|
||||
} while ( discard_size > 0 );
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
/* Load value[i] */
|
||||
"ld.d %2, %0, -8\n\t"
|
||||
/* Shift right */
|
||||
"andi %4, %2, 1\n\t"
|
||||
"xor %2, %2, %4\n\t"
|
||||
"or %2, %2, %3\n\t"
|
||||
"move %3, %4\n\t"
|
||||
"rotri.d %2, %2, 1\n\t"
|
||||
/* Store value[i] */
|
||||
"st.d %2, %0, -8\n\t"
|
||||
/* Loop */
|
||||
"addi.d %0, %0, -8\n\t"
|
||||
"addi.w %1, %1, -1\n\t"
|
||||
"bnez %1, 1b\n\t"
|
||||
: "=r" ( discard_value ),
|
||||
"=r" ( discard_size ),
|
||||
"=r" ( discard_value_i ),
|
||||
"=r" ( discard_carry ),
|
||||
"=r" ( discard_temp ),
|
||||
"+m" ( *value )
|
||||
: "0" ( value0 + size ), "1" ( size ), "3" ( 0 )
|
||||
: "cc" );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,7 +358,9 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint64_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint64_t *multiplier0,
|
||||
uint64_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint64_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
@ -12,4 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** Page shift */
|
||||
#define PAGE_SHIFT 12
|
||||
|
||||
#include <ipxe/loong64_io.h>
|
||||
|
||||
#endif /* _BITS_IO_H */
|
||||
|
||||
12
src/arch/loong64/include/bits/mp.h
Normal file
12
src/arch/loong64/include/bits/mp.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _BITS_MP_H
|
||||
#define _BITS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* LoongArch64-specific multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_MP_H */
|
||||
@ -9,4 +9,6 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#endif /* _BITS_MAP_H */
|
||||
#include <ipxe/efi/efiloong64_nap.h>
|
||||
|
||||
#endif /* _BITS_NAP_H */
|
||||
|
||||
18
src/arch/loong64/include/ipxe/efi/efiloong64_nap.h
Normal file
18
src/arch/loong64/include/ipxe/efi/efiloong64_nap.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef _IPXE_EFILOONG64_NAP_H
|
||||
#define _IPXE_EFILOONG64_NAP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EFI CPU sleeping
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef NAP_EFILOONG64
|
||||
#define NAP_PREFIX_efiloong64
|
||||
#else
|
||||
#define NAP_PREFIX_efiloong64 __efiloong64_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_EFILOONG64_NAP_H */
|
||||
82
src/arch/loong64/include/ipxe/loong64_io.h
Normal file
82
src/arch/loong64/include/ipxe/loong64_io.h
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef _IPXE_LOONG64_IO_H
|
||||
#define _IPXE_LOONG64_IO_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE I/O API for LoongArch64
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef IOAPI_LOONG64
|
||||
#define IOAPI_PREFIX_loong64
|
||||
#else
|
||||
#define IOAPI_PREFIX_loong64 __loong64_
|
||||
#endif
|
||||
|
||||
#include <ipxe/dummy_pio.h>
|
||||
|
||||
/*
|
||||
* Memory space mappings
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Physical<->Bus address mappings
|
||||
*
|
||||
*/
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( loong64, phys_to_bus ) ( unsigned long phys_addr ) {
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
static inline __always_inline unsigned long
|
||||
IOAPI_INLINE ( loong64, bus_to_phys ) ( unsigned long bus_addr ) {
|
||||
return bus_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* MMIO reads and writes up to native word size
|
||||
*
|
||||
*/
|
||||
|
||||
#define LOONG64_READX( _suffix, _type, _insn_suffix ) \
|
||||
static inline __always_inline _type \
|
||||
IOAPI_INLINE ( loong64, read ## _suffix ) ( volatile _type *io_addr ) { \
|
||||
_type data; \
|
||||
__asm__ __volatile__ ( "ld." _insn_suffix " %0, %1" \
|
||||
: "=r" ( data ) : "m" ( *io_addr ) ); \
|
||||
return data; \
|
||||
}
|
||||
LOONG64_READX ( b, uint8_t, "bu");
|
||||
LOONG64_READX ( w, uint16_t, "hu");
|
||||
LOONG64_READX ( l, uint32_t, "wu");
|
||||
LOONG64_READX ( q, uint64_t, "d");
|
||||
|
||||
#define LOONG64_WRITEX( _suffix, _type, _insn_suffix ) \
|
||||
static inline __always_inline void \
|
||||
IOAPI_INLINE ( loong64, write ## _suffix ) ( _type data, \
|
||||
volatile _type *io_addr ) { \
|
||||
__asm__ __volatile__ ( "st." _insn_suffix " %0, %1" \
|
||||
: : "r" ( data ), "m" ( *io_addr ) ); \
|
||||
}
|
||||
LOONG64_WRITEX ( b, uint8_t, "b");
|
||||
LOONG64_WRITEX ( w, uint16_t, "h");
|
||||
LOONG64_WRITEX ( l, uint32_t, "w" );
|
||||
LOONG64_WRITEX ( q, uint64_t, "d");
|
||||
|
||||
/*
|
||||
* Memory barrier
|
||||
*
|
||||
*/
|
||||
static inline __always_inline void
|
||||
IOAPI_INLINE ( loong64, mb ) ( void ) {
|
||||
__asm__ __volatile__ ( "dbar 0" );
|
||||
}
|
||||
|
||||
/* Dummy PIO */
|
||||
DUMMY_PIO ( loong64 );
|
||||
|
||||
#endif /* _IPXE_LOONG64_IO_H */
|
||||
57
src/arch/loong64/interface/efi/efiloong64_nap.c
Normal file
57
src/arch/loong64/interface/efi/efiloong64_nap.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/nap.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE CPU sleeping API for EFI
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sleep until next interrupt
|
||||
*
|
||||
*/
|
||||
static void efiloong64_cpu_nap ( void ) {
|
||||
/*
|
||||
* I can't find any EFI API that allows us to put the CPU to
|
||||
* sleep. The CpuSleep() function is defined in CpuLib.h, but
|
||||
* isn't part of any exposed protocol so we have no way to
|
||||
* call it.
|
||||
*
|
||||
* The EFI shell doesn't seem to bother sleeping the CPU; it
|
||||
* just sits there idly burning power.
|
||||
*
|
||||
* If a shutdown is in progess, there may be nothing to
|
||||
* generate an interrupt since the timer is disabled in the
|
||||
* first step of ExitBootServices().
|
||||
*/
|
||||
if ( ! efi_shutdown_in_progress )
|
||||
__asm__ __volatile__ ( "idle 0" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efiloong64, cpu_nap, efiloong64_cpu_nap );
|
||||
@ -13,6 +13,13 @@ LDSCRIPT_PREFIX = arch/x86/scripts/prefixonly.lds
|
||||
#
|
||||
LDFLAGS += -N --no-check-sections
|
||||
|
||||
# Do not warn about RWX segments (required by most prefixes)
|
||||
#
|
||||
WRWX_TEST = $(LD) --warn-rwx-segments --version 2>&1 > /dev/null
|
||||
WRWX_FLAGS := $(shell [ -z "`$(WRWX_TEST)`" ] && \
|
||||
$(ECHO) '--no-warn-rwx-segments')
|
||||
LDFLAGS += $(WRWX_FLAGS)
|
||||
|
||||
# Media types.
|
||||
#
|
||||
MEDIA += rom
|
||||
@ -54,9 +61,15 @@ LIST_NAME_mrom := ROMS
|
||||
LIST_NAME_pcirom := ROMS
|
||||
LIST_NAME_isarom := ROMS
|
||||
|
||||
# ISO or FAT filesystem images
|
||||
# ISO images
|
||||
NON_AUTO_MEDIA += iso
|
||||
$(BIN)/%.iso $(BIN)/%.sdsk: $(BIN)/%.lkrn util/genfsimg
|
||||
$(BIN)/%.iso : $(BIN)/%.lkrn util/genfsimg
|
||||
$(QM)$(ECHO) " [GENFSIMG] $@"
|
||||
$(Q)util/genfsimg -o $@ $<
|
||||
|
||||
# FAT filesystem images (via syslinux)
|
||||
NON_AUTO_MEDIA += sdsk
|
||||
$(BIN)/%.sdsk : $(BIN)/%.lkrn util/genfsimg
|
||||
$(QM)$(ECHO) " [GENFSIMG] $@"
|
||||
$(Q)util/genfsimg -o $@ $<
|
||||
|
||||
|
||||
197
src/arch/x86/core/mpcall.S
Normal file
197
src/arch/x86/core/mpcall.S
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Multiprocessor functions
|
||||
*
|
||||
*/
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
|
||||
/* Selectively assemble code for 32-bit/64-bit builds */
|
||||
#if defined ( __x86_64__ ) && ! defined ( PLATFORM_pcbios )
|
||||
#define codemp code64
|
||||
#define DI rdi
|
||||
#define SP rsp
|
||||
#define if32 if 0
|
||||
#define if64 if 1
|
||||
#else
|
||||
#define codemp code32
|
||||
#define DI edi
|
||||
#define SP esp
|
||||
#define if32 if 1
|
||||
#define if64 if 0
|
||||
#endif
|
||||
|
||||
/* Standard features CPUID leaf */
|
||||
#define CPUID_FEATURES 0x00000001
|
||||
|
||||
/* x2APIC is supported */
|
||||
#define CPUID_FEATURES_ECX_X2APIC 0x00200000
|
||||
|
||||
/* Extended topology enumeration CPUID leaf */
|
||||
#define CPUID_XT_ENUM 0x0000000b
|
||||
|
||||
/*
|
||||
* Call multiprocessor function from C code
|
||||
*
|
||||
* Parameters:
|
||||
* 4(%esp)/%rdi Multiprocessor function
|
||||
* 8(%esp)/%rsi Opaque data pointer
|
||||
*/
|
||||
.section ".text.mp_call", "ax", @progbits
|
||||
.codemp
|
||||
.globl mp_call
|
||||
mp_call:
|
||||
.if64 /* Preserve registers, load incoming parameters into registers */
|
||||
pushq %rax
|
||||
pushq %rcx
|
||||
pushq %rdx
|
||||
pushq %rbx
|
||||
pushq %rsp
|
||||
pushq %rbp
|
||||
pushq %rsi
|
||||
pushq %rdi
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
pushq %r11
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
.else
|
||||
pushal
|
||||
movl 36(%esp), %eax
|
||||
movl 40(%esp), %edx
|
||||
.endif
|
||||
/* Call multiprocessor function */
|
||||
call mp_jump
|
||||
|
||||
.if64 /* Restore registers and return */
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
popq %rbp
|
||||
leaq 8(%rsp), %rsp /* discard */
|
||||
popq %rbx
|
||||
popq %rdx
|
||||
popq %rcx
|
||||
popq %rax
|
||||
.else
|
||||
popal
|
||||
.endif
|
||||
ret
|
||||
.size mp_call, . - mp_call
|
||||
|
||||
/*
|
||||
* Jump to multiprocessor function
|
||||
*
|
||||
* Parameters:
|
||||
* %eax/%rdi Multiprocessor function
|
||||
* %edx/%rsi Opaque data pointer
|
||||
* %esp/%rsp Stack, or NULL to halt AP upon completion
|
||||
*
|
||||
* Obtain the CPU identifier (i.e. the APIC ID) and perform a tail
|
||||
* call into the specified multiprocessor function.
|
||||
*
|
||||
* This code may run with no stack on an application processor.
|
||||
*/
|
||||
.section ".text.mp_jump", "ax", @progbits
|
||||
.codemp
|
||||
.globl mp_jump
|
||||
mp_jump:
|
||||
.if32 /* Move function parameters to available registers */
|
||||
movl %eax, %edi
|
||||
movl %edx, %esi
|
||||
.endif
|
||||
|
||||
/* Get 8-bit APIC ID and x2APIC feature bit */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
shrl $24, %ebx
|
||||
movl %ebx, %edx
|
||||
|
||||
/* Get 32-bit x2APIC ID if applicable */
|
||||
testl $CPUID_FEATURES_ECX_X2APIC, %ecx
|
||||
jz 1f
|
||||
movl $CPUID_XT_ENUM, %eax
|
||||
xorl %ecx, %ecx
|
||||
cpuid
|
||||
1:
|
||||
|
||||
.if64 /* Tail call to function */
|
||||
movq %rdi, %rax
|
||||
movq %rsi, %rdi
|
||||
movl %edx, %esi
|
||||
jmp *%rax
|
||||
.else
|
||||
movl %esi, %eax
|
||||
jmp *%edi
|
||||
.endif
|
||||
.size mp_jump, . - mp_jump
|
||||
|
||||
/*
|
||||
* Update maximum CPU identifier
|
||||
*
|
||||
* Parameters:
|
||||
* %eax/%rdi Pointer to shared maximum APIC ID
|
||||
* %edx/%rsi CPU identifier (APIC ID)
|
||||
* %esp/%rsp Stack, or NULL to halt AP upon completion
|
||||
*
|
||||
* This code may run with no stack on an application processor.
|
||||
*/
|
||||
.section ".text.mp_update_max_cpuid", "ax", @progbits
|
||||
.codemp
|
||||
.globl mp_update_max_cpuid
|
||||
mp_update_max_cpuid:
|
||||
.if32 /* Move function parameters to available registers */
|
||||
movl %eax, %edi
|
||||
movl %edx, %esi
|
||||
.endif
|
||||
/* Update maximum APIC ID (atomically) */
|
||||
movl (%DI), %eax
|
||||
1: cmpl %esi, %eax
|
||||
jae 2f
|
||||
lock cmpxchgl %esi, (%DI)
|
||||
jnz 1b
|
||||
2:
|
||||
/* Return to caller (if stack exists), or halt application processor */
|
||||
test %SP, %SP
|
||||
jz 3f
|
||||
ret
|
||||
3: cli
|
||||
hlt
|
||||
jmp 3b
|
||||
.size mp_update_max_cpuid, . - mp_update_max_cpuid
|
||||
@ -22,9 +22,9 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Set/clear CF on the stack as appropriate, assumes stack is as it should
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define STACK_SIZE 8192
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
|
||||
257
src/arch/x86/core/ucode_mp.S
Normal file
257
src/arch/x86/core/ucode_mp.S
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Microcode updates
|
||||
*
|
||||
*/
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
|
||||
/* Selectively assemble code for 32-bit/64-bit builds */
|
||||
#if defined ( __x86_64__ ) && ! defined ( PLATFORM_pcbios )
|
||||
#define codemp code64
|
||||
#define AX rax
|
||||
#define BX rbx
|
||||
#define CX rcx
|
||||
#define DX rdx
|
||||
#define SI rsi
|
||||
#define DI rdi
|
||||
#define BP rbp
|
||||
#define SP rsp
|
||||
#define if32 if 0
|
||||
#define if64 if 1
|
||||
#else
|
||||
#define codemp code32
|
||||
#define AX eax
|
||||
#define BX ebx
|
||||
#define CX ecx
|
||||
#define DX edx
|
||||
#define SI esi
|
||||
#define DI edi
|
||||
#define BP ebp
|
||||
#define SP esp
|
||||
#define if32 if 1
|
||||
#define if64 if 0
|
||||
#endif
|
||||
|
||||
/* Standard features CPUID leaf */
|
||||
#define CPUID_FEATURES 0x00000001
|
||||
|
||||
/* BIOS update signature MSR */
|
||||
#define MSR_BIOS_SIGN_ID 0x0000008b
|
||||
|
||||
/** Microcode update control layout
|
||||
*
|
||||
* This must match the layout of struct ucode_control.
|
||||
*/
|
||||
.struct 0
|
||||
CONTROL_DESC:
|
||||
.space 8
|
||||
CONTROL_STATUS:
|
||||
.space 8
|
||||
CONTROL_TRIGGER_MSR:
|
||||
.space 4
|
||||
CONTROL_APIC_MAX:
|
||||
.space 4
|
||||
CONTROL_APIC_UNEXPECTED:
|
||||
.space 4
|
||||
CONTROL_APIC_MASK:
|
||||
.space 4
|
||||
CONTROL_APIC_TEST:
|
||||
.space 4
|
||||
CONTROL_VER_CLEAR:
|
||||
.space 1
|
||||
CONTROL_VER_HIGH:
|
||||
.space 1
|
||||
CONTROL_LEN:
|
||||
|
||||
/* We use register %ebp/%rbp to hold the address of the update control */
|
||||
#define CONTROL BP
|
||||
|
||||
/* Microcode update descriptor layout
|
||||
*
|
||||
* This must match the layout of struct ucode_descriptor.
|
||||
*/
|
||||
.struct 0
|
||||
DESC_SIGNATURE:
|
||||
.space 4
|
||||
DESC_VERSION:
|
||||
.space 4
|
||||
DESC_ADDRESS:
|
||||
.space 8
|
||||
DESC_LEN:
|
||||
|
||||
/* We use register %esi/%rsi to hold the address of the descriptor */
|
||||
#define DESC SI
|
||||
|
||||
/** Microcode update status report layout
|
||||
*
|
||||
* This must match the layout of struct ucode_status.
|
||||
*/
|
||||
.struct 0
|
||||
STATUS_SIGNATURE:
|
||||
.space 4
|
||||
STATUS_ID:
|
||||
.space 4
|
||||
STATUS_BEFORE:
|
||||
.space 4
|
||||
STATUS_AFTER:
|
||||
.space 4
|
||||
STATUS_LEN:
|
||||
.equ LOG2_STATUS_LEN, 4
|
||||
.if ( 1 << LOG2_STATUS_LEN ) - STATUS_LEN
|
||||
.error "LOG2_STATUS_LEN value is incorrect"
|
||||
.endif
|
||||
|
||||
/* We use register %edi/%rdi to hold the address of the status report */
|
||||
#define STATUS DI
|
||||
|
||||
/*
|
||||
* Update microcode
|
||||
*
|
||||
* Parameters:
|
||||
* %eax/%rdi Microcode update structure
|
||||
* %edx/%rsi CPU identifier (APIC ID)
|
||||
* %esp/%rsp Stack, or NULL to halt AP upon completion
|
||||
*
|
||||
* This code may run with no stack on an application processor (AP).
|
||||
* All values must be held in registers, and no subroutine calls are
|
||||
* possible. No firmware routines may be called.
|
||||
*
|
||||
* Since cpuid/rdmsr/wrmsr require the use of %eax, %ebx, %ecx, and
|
||||
* %edx, we have essentially only three registers available for
|
||||
* long-term state.
|
||||
*/
|
||||
.text
|
||||
.globl ucode_update
|
||||
.codemp
|
||||
.section ".text.ucode_update", "ax", @progbits
|
||||
ucode_update:
|
||||
|
||||
.if64 /* Get input parameters */
|
||||
movq %rdi, %CONTROL
|
||||
movl %esi, %edx
|
||||
.else
|
||||
movl %eax, %CONTROL
|
||||
.endif
|
||||
/* Check against maximum expected APIC ID */
|
||||
cmpl CONTROL_APIC_MAX(%CONTROL), %edx
|
||||
jbe 1f
|
||||
movl %edx, CONTROL_APIC_UNEXPECTED(%CONTROL)
|
||||
jmp done
|
||||
1:
|
||||
/* Calculate per-CPU status report buffer address */
|
||||
mov %DX, %STATUS
|
||||
shl $LOG2_STATUS_LEN, %STATUS
|
||||
add CONTROL_STATUS(%CONTROL), %STATUS
|
||||
|
||||
/* Report APIC ID */
|
||||
movl %edx, STATUS_ID(%STATUS)
|
||||
|
||||
/* Get and report CPU signature */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
movl %eax, STATUS_SIGNATURE(%STATUS)
|
||||
|
||||
/* Check APIC ID mask */
|
||||
movl STATUS_ID(%STATUS), %eax
|
||||
andl CONTROL_APIC_MASK(%CONTROL), %eax
|
||||
cmpl CONTROL_APIC_TEST(%CONTROL), %eax
|
||||
jne done
|
||||
|
||||
/* Clear BIOS_SIGN_ID MSR if applicable */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
xorl %eax, %eax
|
||||
xorl %edx, %edx
|
||||
testb $0xff, CONTROL_VER_CLEAR(%CONTROL)
|
||||
jz 1f
|
||||
wrmsr
|
||||
1:
|
||||
/* Get CPU signature to repopulate BIOS_SIGN_ID MSR (for Intel) */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
|
||||
/* Get initial microcode version */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
rdmsr
|
||||
testb $0xff, CONTROL_VER_HIGH(%CONTROL)
|
||||
jz 1f
|
||||
movl %edx, %eax
|
||||
1: movl %eax, STATUS_BEFORE(%STATUS)
|
||||
|
||||
/* Get start of descriptor list */
|
||||
mov CONTROL_DESC(%CONTROL), %DESC
|
||||
sub $DESC_LEN, %DESC
|
||||
|
||||
1: /* Walk update descriptor list to find a matching CPU signature */
|
||||
add $DESC_LEN, %DESC
|
||||
movl DESC_SIGNATURE(%DESC), %eax
|
||||
testl %eax, %eax
|
||||
jz noload
|
||||
cmpl STATUS_SIGNATURE(%STATUS), %eax
|
||||
jne 1b
|
||||
|
||||
/* Compare (signed) microcode versions */
|
||||
movl STATUS_BEFORE(%STATUS), %eax
|
||||
cmpl DESC_VERSION(%DESC), %eax
|
||||
jge noload
|
||||
|
||||
/* Load microcode update */
|
||||
movl CONTROL_TRIGGER_MSR(%CONTROL), %ecx
|
||||
movl (DESC_ADDRESS + 0)(%DESC), %eax
|
||||
movl (DESC_ADDRESS + 4)(%DESC), %edx
|
||||
wrmsr
|
||||
|
||||
noload: /* Clear BIOS_SIGN_ID MSR if applicable */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
xorl %eax, %eax
|
||||
xorl %edx, %edx
|
||||
testb $0xff, CONTROL_VER_CLEAR(%CONTROL)
|
||||
jz 1f
|
||||
wrmsr
|
||||
1:
|
||||
/* Get CPU signature to repopulate BIOS_SIGN_ID MSR (for Intel) */
|
||||
movl $CPUID_FEATURES, %eax
|
||||
cpuid
|
||||
|
||||
/* Get and report final microcode version */
|
||||
movl $MSR_BIOS_SIGN_ID, %ecx
|
||||
rdmsr
|
||||
testb $0xff, CONTROL_VER_HIGH(%CONTROL)
|
||||
jz 1f
|
||||
movl %edx, %eax
|
||||
1: movl %eax, STATUS_AFTER(%STATUS)
|
||||
|
||||
done: /* Return to caller (if stack exists), or halt application processor */
|
||||
test %SP, %SP
|
||||
jz 1f
|
||||
ret
|
||||
1: cli
|
||||
hlt
|
||||
jmp 1b
|
||||
.size ucode_update, . - ucode_update
|
||||
@ -36,19 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Multiply big integers
|
||||
*
|
||||
* @v multiplicand0 Element 0 of big integer to be multiplied
|
||||
* @v multiplicand_size Number of elements in multiplicand
|
||||
* @v multiplier0 Element 0 of big integer to be multiplied
|
||||
* @v multiplier_size Number of elements in multiplier
|
||||
* @v result0 Element 0 of big integer to hold result
|
||||
* @v size Number of elements
|
||||
*/
|
||||
void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *result0, unsigned int size ) {
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
|
||||
( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
|
||||
( ( const void * ) multiplier0 );
|
||||
bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
|
||||
( ( void * ) result0 );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *result0 ) {
|
||||
unsigned int result_size = ( multiplicand_size + multiplier_size );
|
||||
const bigint_t ( multiplicand_size ) __attribute__ (( may_alias ))
|
||||
*multiplicand = ( ( const void * ) multiplicand0 );
|
||||
const bigint_t ( multiplier_size ) __attribute__ (( may_alias ))
|
||||
*multiplier = ( ( const void * ) multiplier0 );
|
||||
bigint_t ( result_size ) __attribute__ (( may_alias ))
|
||||
*result = ( ( void * ) result0 );
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
uint32_t multiplicand_element;
|
||||
@ -62,9 +66,9 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
memset ( result, 0, sizeof ( *result ) );
|
||||
|
||||
/* Multiply integers one element at a time */
|
||||
for ( i = 0 ; i < size ; i++ ) {
|
||||
for ( i = 0 ; i < multiplicand_size ; i++ ) {
|
||||
multiplicand_element = multiplicand->element[i];
|
||||
for ( j = 0 ; j < size ; j++ ) {
|
||||
for ( j = 0 ; j < multiplier_size ; j++ ) {
|
||||
multiplier_element = multiplier->element[j];
|
||||
result_elements = &result->element[ i + j ];
|
||||
/* Perform a single multiply, and add the
|
||||
@ -73,7 +77,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
* never overflow beyond the end of the
|
||||
* result, since:
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mull %5\n\t"
|
||||
"addl %%eax, (%6,%2,4)\n\t"
|
||||
|
||||
@ -10,9 +10,9 @@ FILE_LICENCE ( GPL2_OR_LATER )
|
||||
#define PIC1_ICR 0x20
|
||||
#define PIC2_ICR 0xa0
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
.section ".text16", "ax", @progbits
|
||||
.globl undiisr
|
||||
|
||||
@ -355,6 +355,10 @@ static size_t bzimage_load_initrd ( struct image *image,
|
||||
size_t offset;
|
||||
size_t pad_len;
|
||||
|
||||
/* Skip hidden images */
|
||||
if ( initrd->flags & IMAGE_HIDDEN )
|
||||
return 0;
|
||||
|
||||
/* Create cpio header for non-prebuilt images */
|
||||
offset = cpio_header ( initrd, &cpio );
|
||||
|
||||
|
||||
@ -204,6 +204,10 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip hidden images */
|
||||
if ( module_image->flags & IMAGE_HIDDEN )
|
||||
continue;
|
||||
|
||||
/* Page-align the module */
|
||||
start = ( ( start + 0xfff ) & ~0xfff );
|
||||
|
||||
|
||||
798
src/arch/x86/image/ucode.c
Normal file
798
src/arch/x86/image/ucode.c
Normal file
@ -0,0 +1,798 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Microcode updates
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/umalloc.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/msr.h>
|
||||
#include <ipxe/mp.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/ucode.h>
|
||||
|
||||
/**
|
||||
* Maximum number of hyperthread siblings
|
||||
*
|
||||
* Microcode updates must not be performed on hyperthread siblings at
|
||||
* the same time, since they share microcode storage.
|
||||
*
|
||||
* Hyperthread siblings are always the lowest level of the CPU
|
||||
* topology and correspond to the least significant bits of the APIC
|
||||
* ID. We may therefore avoid collisions by performing the microcode
|
||||
* updates in batches, with each batch targeting just one value for
|
||||
* the least significant N bits of the APIC ID.
|
||||
*
|
||||
* We assume that no CPUs exist with more than this number of
|
||||
* hyperthread siblings. (This must be a power of two.)
|
||||
*/
|
||||
#define UCODE_MAX_HT 8
|
||||
|
||||
/** Time to wait for a microcode update to complete */
|
||||
#define UCODE_WAIT_MS 10
|
||||
|
||||
/** A CPU vendor string */
|
||||
union ucode_vendor_id {
|
||||
/** CPUID registers */
|
||||
uint32_t dword[3];
|
||||
/** Human-readable string */
|
||||
uint8_t string[12];
|
||||
};
|
||||
|
||||
/** A CPU vendor */
|
||||
struct ucode_vendor {
|
||||
/** Vendor string */
|
||||
union ucode_vendor_id id;
|
||||
/** Microcode load trigger MSR */
|
||||
uint32_t trigger_msr;
|
||||
/** Microcode version requires manual clear */
|
||||
uint8_t ver_clear;
|
||||
/** Microcode version is reported via high dword */
|
||||
uint8_t ver_high;
|
||||
};
|
||||
|
||||
/** A microcode update */
|
||||
struct ucode_update {
|
||||
/** CPU vendor, if known */
|
||||
struct ucode_vendor *vendor;
|
||||
/** Boot processor CPU signature */
|
||||
uint32_t signature;
|
||||
/** Platform ID */
|
||||
uint32_t platform;
|
||||
/** Number of potentially relevant signatures found */
|
||||
unsigned int count;
|
||||
/** Update descriptors (if being populated) */
|
||||
struct ucode_descriptor *desc;
|
||||
};
|
||||
|
||||
/** A microcode update summary */
|
||||
struct ucode_summary {
|
||||
/** Number of CPUs processed */
|
||||
unsigned int count;
|
||||
/** Lowest observed microcode version */
|
||||
int32_t low;
|
||||
/** Highest observed microcode version */
|
||||
int32_t high;
|
||||
};
|
||||
|
||||
/** Intel CPU vendor */
|
||||
static struct ucode_vendor ucode_intel = {
|
||||
.id = { .string = "GenuineIntel" },
|
||||
.ver_clear = 1,
|
||||
.ver_high = 1,
|
||||
.trigger_msr = MSR_UCODE_TRIGGER_INTEL,
|
||||
};
|
||||
|
||||
/** AMD CPU vendor */
|
||||
static struct ucode_vendor ucode_amd = {
|
||||
.id = { .string = "AuthenticAMD" },
|
||||
.trigger_msr = MSR_UCODE_TRIGGER_AMD,
|
||||
};
|
||||
|
||||
/** List of known CPU vendors */
|
||||
static struct ucode_vendor *ucode_vendors[] = {
|
||||
&ucode_intel,
|
||||
&ucode_amd,
|
||||
};
|
||||
|
||||
/**
|
||||
* Get CPU vendor name (for debugging)
|
||||
*
|
||||
* @v vendor CPU vendor
|
||||
* @ret name Name
|
||||
*/
|
||||
static const char * ucode_vendor_name ( const union ucode_vendor_id *vendor ) {
|
||||
static union {
|
||||
union ucode_vendor_id vendor;
|
||||
char text[ sizeof ( *vendor ) + 1 /* NUL */ ];
|
||||
} u;
|
||||
|
||||
/* Construct name */
|
||||
memcpy ( &u.vendor, vendor, sizeof ( u.vendor ) );
|
||||
u.text[ sizeof ( u.text ) - 1 ] = '\0';
|
||||
return u.text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check status report
|
||||
*
|
||||
* @v update Microcode update
|
||||
* @v control Microcode update control
|
||||
* @v summary Microcode update summary
|
||||
* @v id APIC ID
|
||||
* @v optional Status report is optional
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_status ( struct ucode_update *update,
|
||||
struct ucode_control *control,
|
||||
struct ucode_summary *summary,
|
||||
unsigned int id, int optional ) {
|
||||
struct ucode_status status;
|
||||
struct ucode_descriptor *desc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( id <= control->apic_max );
|
||||
|
||||
/* Read status report */
|
||||
copy_from_user ( &status, phys_to_user ( control->status ),
|
||||
( id * sizeof ( status ) ), sizeof ( status ) );
|
||||
|
||||
/* Ignore empty optional status reports */
|
||||
if ( optional && ( ! status.signature ) )
|
||||
return 0;
|
||||
DBGC ( update, "UCODE %#08x signature %#08x ucode %#08x->%#08x\n",
|
||||
id, status.signature, status.before, status.after );
|
||||
|
||||
/* Check CPU signature */
|
||||
if ( ! status.signature ) {
|
||||
DBGC2 ( update, "UCODE %#08x has no signature\n", id );
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Check APIC ID is correct */
|
||||
if ( status.id != id ) {
|
||||
DBGC ( update, "UCODE %#08x wrong APIC ID %#08x\n",
|
||||
id, status.id );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check that maximum APIC ID was not exceeded */
|
||||
if ( control->apic_unexpected ) {
|
||||
DBGC ( update, "UCODE %#08x saw unexpected APIC ID %#08x\n",
|
||||
id, control->apic_unexpected );
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Check microcode was not downgraded */
|
||||
if ( status.after < status.before ) {
|
||||
DBGC ( update, "UCODE %#08x was downgraded %#08x->%#08x\n",
|
||||
id, status.before, status.after );
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/* Check that expected updates (if any) were applied */
|
||||
for ( desc = update->desc ; desc->signature ; desc++ ) {
|
||||
if ( ( desc->signature == status.signature ) &&
|
||||
( status.after < desc->version ) ) {
|
||||
DBGC ( update, "UCODE %#08x failed update %#08x->%#08x "
|
||||
"(wanted %#08x)\n", id, status.before,
|
||||
status.after, desc->version );
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update summary */
|
||||
summary->count++;
|
||||
if ( status.before < summary->low )
|
||||
summary->low = status.before;
|
||||
if ( status.after > summary->high )
|
||||
summary->high = status.after;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update microcode on all CPUs
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v update Microcode update
|
||||
* @v summary Microcode update summary to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_update_all ( struct image *image,
|
||||
struct ucode_update *update,
|
||||
struct ucode_summary *summary ) {
|
||||
struct ucode_control control;
|
||||
struct ucode_vendor *vendor;
|
||||
userptr_t status;
|
||||
unsigned int max;
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Initialise summary */
|
||||
summary->count = 0;
|
||||
summary->low = UCODE_VERSION_MAX;
|
||||
summary->high = UCODE_VERSION_MIN;
|
||||
|
||||
/* Allocate status reports */
|
||||
max = mp_max_cpuid();
|
||||
len = ( ( max + 1 ) * sizeof ( struct ucode_status ) );
|
||||
status = umalloc ( len );
|
||||
if ( ! status ) {
|
||||
DBGC ( image, "UCODE %s could not allocate %d status reports\n",
|
||||
image->name, ( max + 1 ) );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
memset_user ( status, 0, 0, len );
|
||||
|
||||
/* Construct control structure */
|
||||
memset ( &control, 0, sizeof ( control ) );
|
||||
control.desc = virt_to_phys ( update->desc );
|
||||
control.status = user_to_phys ( status, 0 );
|
||||
vendor = update->vendor;
|
||||
if ( vendor ) {
|
||||
control.ver_clear = vendor->ver_clear;
|
||||
control.ver_high = vendor->ver_high;
|
||||
control.trigger_msr = vendor->trigger_msr;
|
||||
} else {
|
||||
assert ( update->count == 0 );
|
||||
}
|
||||
control.apic_max = max;
|
||||
|
||||
/* Update microcode on boot processor */
|
||||
mp_exec_boot ( ucode_update, &control );
|
||||
if ( ( rc = ucode_status ( update, &control, summary,
|
||||
mp_boot_cpuid(), 0 ) ) != 0 ) {
|
||||
DBGC ( image, "UCODE %s failed on boot processor: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
goto err_boot;
|
||||
}
|
||||
|
||||
/* Update microcode on application processors, avoiding
|
||||
* simultaneous updates on hyperthread siblings.
|
||||
*/
|
||||
build_assert ( ( UCODE_MAX_HT & ( UCODE_MAX_HT - 1 ) ) == 0 );
|
||||
control.apic_mask = ( UCODE_MAX_HT - 1 );
|
||||
for ( ; control.apic_test <= control.apic_mask ; control.apic_test++ ) {
|
||||
mp_start_all ( ucode_update, &control );
|
||||
mdelay ( UCODE_WAIT_MS );
|
||||
}
|
||||
|
||||
/* Check status reports */
|
||||
summary->count = 0;
|
||||
for ( i = 0 ; i <= max ; i++ ) {
|
||||
if ( ( rc = ucode_status ( update, &control, summary,
|
||||
i, 1 ) ) != 0 ) {
|
||||
goto err_status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_status:
|
||||
err_boot:
|
||||
ufree ( status );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add descriptor to list (if applicable)
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset within image
|
||||
* @v vendor CPU vendor
|
||||
* @v desc Microcode descriptor
|
||||
* @v platforms Supported platforms, or 0 for all platforms
|
||||
* @v update Microcode update
|
||||
*/
|
||||
static void ucode_describe ( struct image *image, size_t start,
|
||||
const struct ucode_vendor *vendor,
|
||||
const struct ucode_descriptor *desc,
|
||||
uint32_t platforms, struct ucode_update *update ) {
|
||||
|
||||
/* Dump descriptor information */
|
||||
DBGC2 ( image, "UCODE %s+%#04zx %s %#08x", image->name, start,
|
||||
ucode_vendor_name ( &vendor->id ), desc->signature );
|
||||
if ( platforms )
|
||||
DBGC2 ( image, " (%#02x)", platforms );
|
||||
DBGC2 ( image, " version %#08x\n", desc->version );
|
||||
|
||||
/* Check applicability */
|
||||
if ( vendor != update->vendor )
|
||||
return;
|
||||
if ( ( desc->signature ^ update->signature ) & UCODE_SIGNATURE_MASK )
|
||||
return;
|
||||
if ( platforms && ( ! ( platforms & update->platform ) ) )
|
||||
return;
|
||||
|
||||
/* Add descriptor, if applicable */
|
||||
if ( update->desc ) {
|
||||
memcpy ( &update->desc[update->count], desc, sizeof ( *desc ) );
|
||||
DBGC ( image, "UCODE %s+%#04zx found %s %#08x version %#08x\n",
|
||||
image->name, start, ucode_vendor_name ( &vendor->id ),
|
||||
desc->signature, desc->version );
|
||||
}
|
||||
update->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify checksum
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset
|
||||
* @v len Length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_verify ( struct image *image, size_t start, size_t len ) {
|
||||
uint32_t checksum = 0;
|
||||
uint32_t dword;
|
||||
size_t offset;
|
||||
|
||||
/* Check length is a multiple of dwords */
|
||||
if ( ( len % sizeof ( dword ) ) != 0 ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx invalid length %#zx\n",
|
||||
image->name, start, len );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Calculate checksum */
|
||||
for ( offset = start ; len ;
|
||||
offset += sizeof ( dword ), len -= sizeof ( dword ) ) {
|
||||
copy_from_user ( &dword, image->data, offset,
|
||||
sizeof ( dword ) );
|
||||
checksum += dword;
|
||||
}
|
||||
if ( checksum != 0 ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx bad checksum %#08x\n",
|
||||
image->name, start, checksum );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Intel microcode image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset within image
|
||||
* @v update Microcode update
|
||||
* @ret len Length consumed, or negative error
|
||||
*/
|
||||
static int ucode_parse_intel ( struct image *image, size_t start,
|
||||
struct ucode_update *update ) {
|
||||
struct intel_ucode_header hdr;
|
||||
struct intel_ucode_ext_header exthdr;
|
||||
struct intel_ucode_ext ext;
|
||||
struct ucode_descriptor desc;
|
||||
size_t remaining;
|
||||
size_t offset;
|
||||
size_t data_len;
|
||||
size_t len;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Read header */
|
||||
remaining = ( image->len - start );
|
||||
if ( remaining < sizeof ( hdr ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx too small for Intel header\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
copy_from_user ( &hdr, image->data, start, sizeof ( hdr ) );
|
||||
|
||||
/* Determine lengths */
|
||||
data_len = hdr.data_len;
|
||||
if ( ! data_len )
|
||||
data_len = INTEL_UCODE_DATA_LEN;
|
||||
len = hdr.len;
|
||||
if ( ! len )
|
||||
len = ( sizeof ( hdr ) + data_len );
|
||||
|
||||
/* Verify a selection of fields */
|
||||
if ( ( hdr.hver != INTEL_UCODE_HVER ) ||
|
||||
( hdr.lver != INTEL_UCODE_LVER ) ||
|
||||
( len < sizeof ( hdr ) ) ||
|
||||
( len > remaining ) ||
|
||||
( data_len > ( len - sizeof ( hdr ) ) ) ||
|
||||
( ( data_len % sizeof ( uint32_t ) ) != 0 ) ||
|
||||
( ( len % INTEL_UCODE_ALIGN ) != 0 ) ) {
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is not an Intel update\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is an Intel update\n",
|
||||
image->name, start );
|
||||
|
||||
/* Verify checksum */
|
||||
if ( ( rc = ucode_verify ( image, start, len ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Populate descriptor */
|
||||
desc.signature = hdr.signature;
|
||||
desc.version = hdr.version;
|
||||
desc.address = user_to_phys ( image->data,
|
||||
( start + sizeof ( hdr ) ) );
|
||||
|
||||
/* Add non-extended descriptor, if applicable */
|
||||
ucode_describe ( image, start, &ucode_intel, &desc, hdr.platforms,
|
||||
update );
|
||||
|
||||
/* Construct extended descriptors, if applicable */
|
||||
offset = ( sizeof ( hdr ) + data_len );
|
||||
if ( offset <= ( len - sizeof ( exthdr ) ) ) {
|
||||
|
||||
/* Read extended header */
|
||||
copy_from_user ( &exthdr, image->data, ( start + offset ),
|
||||
sizeof ( exthdr ) );
|
||||
offset += sizeof ( exthdr );
|
||||
|
||||
/* Read extended signatures */
|
||||
for ( i = 0 ; i < exthdr.count ; i++ ) {
|
||||
|
||||
/* Read extended signature */
|
||||
if ( offset > ( len - sizeof ( ext ) ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx extended "
|
||||
"signature overrun\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
copy_from_user ( &ext, image->data, ( start + offset ),
|
||||
sizeof ( ext ) );
|
||||
offset += sizeof ( ext );
|
||||
|
||||
/* Avoid duplicating non-extended descriptor */
|
||||
if ( ( ext.signature == hdr.signature ) &&
|
||||
( ext.platforms == hdr.platforms ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Construct descriptor, if applicable */
|
||||
desc.signature = ext.signature;
|
||||
ucode_describe ( image, start, &ucode_intel, &desc,
|
||||
ext.platforms, update );
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse AMD microcode image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v start Starting offset within image
|
||||
* @v update Microcode update
|
||||
* @ret len Length consumed, or negative error
|
||||
*/
|
||||
static int ucode_parse_amd ( struct image *image, size_t start,
|
||||
struct ucode_update *update ) {
|
||||
struct amd_ucode_header hdr;
|
||||
struct amd_ucode_equivalence equiv;
|
||||
struct amd_ucode_patch_header phdr;
|
||||
struct amd_ucode_patch patch;
|
||||
struct ucode_descriptor desc;
|
||||
size_t remaining;
|
||||
size_t offset;
|
||||
unsigned int count;
|
||||
unsigned int used;
|
||||
unsigned int i;
|
||||
|
||||
/* Read header */
|
||||
remaining = ( image->len - start );
|
||||
if ( remaining < sizeof ( hdr ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx too small for AMD header\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
copy_from_user ( &hdr, image->data, start, sizeof ( hdr ) );
|
||||
|
||||
/* Check header */
|
||||
if ( hdr.magic != AMD_UCODE_MAGIC ) {
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is not an AMD update\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
DBGC2 ( image, "UCODE %s+%#04zx is an AMD update\n",
|
||||
image->name, start );
|
||||
if ( hdr.type != AMD_UCODE_EQUIV_TYPE ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx unsupported equivalence table "
|
||||
"type %d\n", image->name, start, hdr.type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ( hdr.len > ( remaining - sizeof ( hdr ) ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx truncated equivalence table\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Count number of equivalence table entries */
|
||||
offset = sizeof ( hdr );
|
||||
for ( count = 0 ; offset < ( sizeof ( hdr ) + hdr.len ) ;
|
||||
count++, offset += sizeof ( equiv ) ) {
|
||||
copy_from_user ( &equiv, image->data, ( start + offset ),
|
||||
sizeof ( equiv ) );
|
||||
if ( ! equiv.signature )
|
||||
break;
|
||||
}
|
||||
DBGC2 ( image, "UCODE %s+%#04zx has %d equivalence table entries\n",
|
||||
image->name, start, count );
|
||||
|
||||
/* Parse available updates */
|
||||
offset = ( sizeof ( hdr ) + hdr.len );
|
||||
used = 0;
|
||||
while ( used < count ) {
|
||||
|
||||
/* Read patch header */
|
||||
if ( ( offset + sizeof ( phdr ) ) > remaining ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx truncated patch "
|
||||
"header\n", image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
copy_from_user ( &phdr, image->data, ( start + offset ),
|
||||
sizeof ( phdr ) );
|
||||
offset += sizeof ( phdr );
|
||||
|
||||
/* Validate patch header */
|
||||
if ( phdr.type != AMD_UCODE_PATCH_TYPE ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx unsupported patch type "
|
||||
"%d\n", image->name, start, phdr.type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if ( phdr.len < sizeof ( patch ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx underlength patch\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( phdr.len > ( remaining - offset ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx truncated patch\n",
|
||||
image->name, start );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read patch and construct descriptor */
|
||||
copy_from_user ( &patch, image->data, ( start + offset ),
|
||||
sizeof ( patch ) );
|
||||
desc.version = patch.version;
|
||||
desc.address = user_to_phys ( image->data, ( start + offset ) );
|
||||
offset += phdr.len;
|
||||
|
||||
/* Parse equivalence table to find matching signatures */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
copy_from_user ( &equiv, image->data,
|
||||
( start + sizeof ( hdr ) +
|
||||
( i * ( sizeof ( equiv ) ) ) ),
|
||||
sizeof ( equiv ) );
|
||||
if ( patch.id == equiv.id ) {
|
||||
desc.signature = equiv.signature;
|
||||
ucode_describe ( image, start, &ucode_amd,
|
||||
&desc, 0, update );
|
||||
used++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse microcode image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @v update Microcode update
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_parse ( struct image *image, struct ucode_update *update ) {
|
||||
size_t start;
|
||||
int len;
|
||||
|
||||
/* Attempt to parse concatenated microcode updates */
|
||||
for ( start = 0 ; start < image->len ; start += len ) {
|
||||
|
||||
/* Attempt to parse as Intel microcode */
|
||||
len = ucode_parse_intel ( image, start, update );
|
||||
if ( len > 0 )
|
||||
continue;
|
||||
|
||||
/* Attempt to parse as AMD microcode */
|
||||
len = ucode_parse_amd ( image, start, update );
|
||||
if ( len > 0 )
|
||||
continue;
|
||||
|
||||
/* Not a recognised microcode format */
|
||||
DBGC ( image, "UCODE %s+%zx not recognised\n",
|
||||
image->name, start );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute microcode update
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_exec ( struct image *image ) {
|
||||
struct ucode_update update;
|
||||
struct ucode_vendor *vendor;
|
||||
struct ucode_summary summary;
|
||||
union ucode_vendor_id id;
|
||||
uint64_t platform_id;
|
||||
uint32_t discard_a;
|
||||
uint32_t discard_b;
|
||||
uint32_t discard_c;
|
||||
uint32_t discard_d;
|
||||
unsigned int check;
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Initialise update */
|
||||
memset ( &update, 0, sizeof ( update ) );
|
||||
cpuid ( CPUID_VENDOR_ID, 0, &discard_a, &id.dword[0], &id.dword[2],
|
||||
&id.dword[1] );
|
||||
cpuid ( CPUID_FEATURES, 0, &update.signature, &discard_b,
|
||||
&discard_c, &discard_d );
|
||||
|
||||
/* Identify CPU vendor, if recognised */
|
||||
for ( i = 0 ; i < ( sizeof ( ucode_vendors ) /
|
||||
sizeof ( ucode_vendors[0] ) ) ; i++ ) {
|
||||
vendor = ucode_vendors[i];
|
||||
if ( memcmp ( &id, &vendor->id, sizeof ( id ) ) == 0 )
|
||||
update.vendor = vendor;
|
||||
}
|
||||
|
||||
/* Identify platform, if applicable */
|
||||
if ( update.vendor == &ucode_intel ) {
|
||||
platform_id = rdmsr ( MSR_PLATFORM_ID );
|
||||
update.platform =
|
||||
( 1 << MSR_PLATFORM_ID_VALUE ( platform_id ) );
|
||||
}
|
||||
|
||||
/* Count number of matching update descriptors */
|
||||
DBGC ( image, "UCODE %s applying to %s %#08x",
|
||||
image->name, ucode_vendor_name ( &id ), update.signature );
|
||||
if ( update.platform )
|
||||
DBGC ( image, " (%#02x)", update.platform );
|
||||
DBGC ( image, "\n" );
|
||||
if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
|
||||
goto err_count;
|
||||
DBGC ( image, "UCODE %s found %d matching update(s)\n",
|
||||
image->name, update.count );
|
||||
|
||||
/* Allocate descriptors */
|
||||
len = ( ( update.count + 1 /* terminator */ ) *
|
||||
sizeof ( update.desc[0] ) );
|
||||
update.desc = zalloc ( len );
|
||||
if ( ! update.desc ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Populate descriptors */
|
||||
check = update.count;
|
||||
update.count = 0;
|
||||
if ( ( rc = ucode_parse ( image, &update ) ) != 0 )
|
||||
goto err_parse;
|
||||
assert ( check == update.count );
|
||||
|
||||
/* Perform update */
|
||||
if ( ( rc = ucode_update_all ( image, &update, &summary ) ) != 0 )
|
||||
goto err_update;
|
||||
|
||||
/* Print summary if directed to do so */
|
||||
if ( image->cmdline && ( strstr ( image->cmdline, "-v" ) ) ) {
|
||||
printf ( "Microcode: " );
|
||||
if ( summary.low == summary.high ) {
|
||||
printf ( "already version %#x", summary.low );
|
||||
} else {
|
||||
printf ( "updated version %#x->%#x",
|
||||
summary.low, summary.high );
|
||||
}
|
||||
printf ( " (x%d)\n", summary.count );
|
||||
}
|
||||
|
||||
err_update:
|
||||
err_parse:
|
||||
free ( update.desc );
|
||||
err_alloc:
|
||||
err_count:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe microcode update image
|
||||
*
|
||||
* @v image Microcode image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ucode_probe ( struct image *image ) {
|
||||
union {
|
||||
struct intel_ucode_header intel;
|
||||
struct amd_ucode_header amd;
|
||||
} header;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < sizeof ( header ) ) {
|
||||
DBGC ( image, "UCODE %s too short\n", image->name );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Read first microcode image header */
|
||||
copy_from_user ( &header, image->data, 0, sizeof ( header ) );
|
||||
|
||||
/* Check for something that looks like an Intel update
|
||||
*
|
||||
* Intel updates unfortunately have no magic signatures or
|
||||
* other easily verifiable fields. We check a small selection
|
||||
* of header fields that can be easily verified.
|
||||
*
|
||||
* We do not attempt to fully parse the update, since we want
|
||||
* errors to be reported at the point of attempting to execute
|
||||
* the image, and do not want to have a microcode image
|
||||
* erroneously treated as a PXE boot executable.
|
||||
*/
|
||||
if ( ( header.intel.hver == INTEL_UCODE_HVER ) &&
|
||||
( header.intel.lver == INTEL_UCODE_LVER ) &&
|
||||
( ( header.intel.date.century == 0x19 ) ||
|
||||
( ( header.intel.date.century >= 0x20 ) &&
|
||||
( header.intel.date.century <= 0x29 ) ) ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx looks like an Intel update\n",
|
||||
image->name, ( ( size_t ) 0 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for AMD update signature */
|
||||
if ( ( header.amd.magic == AMD_UCODE_MAGIC ) &&
|
||||
( header.amd.type == AMD_UCODE_EQUIV_TYPE ) ) {
|
||||
DBGC ( image, "UCODE %s+%#04zx looks like an AMD update\n",
|
||||
image->name, ( ( size_t ) 0 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/** Microcode update image type */
|
||||
struct image_type ucode_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "ucode",
|
||||
.probe = ucode_probe,
|
||||
.exec = ucode_exec,
|
||||
};
|
||||
@ -323,7 +323,9 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
|
||||
}
|
||||
|
||||
extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
unsigned int multiplicand_size,
|
||||
const uint32_t *multiplier0,
|
||||
uint32_t *value0, unsigned int size );
|
||||
unsigned int multiplier_size,
|
||||
uint32_t *value0 );
|
||||
|
||||
#endif /* _BITS_BIGINT_H */
|
||||
|
||||
@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_sdi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000b0000 )
|
||||
#define ERRFILE_initrd ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000c0000 )
|
||||
#define ERRFILE_pxe_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000d0000 )
|
||||
#define ERRFILE_ucode ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000e0000 )
|
||||
|
||||
#define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
|
||||
#define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
|
||||
|
||||
14
src/arch/x86/include/bits/mp.h
Normal file
14
src/arch/x86/include/bits/mp.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _BITS_MP_H
|
||||
#define _BITS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* x86-specific multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/bios_mp.h>
|
||||
|
||||
#endif /* _BITS_MP_H */
|
||||
32
src/arch/x86/include/ipxe/bios_mp.h
Normal file
32
src/arch/x86/include/ipxe/bios_mp.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef _IPXE_BIOS_MP_H
|
||||
#define _IPXE_BIOS_MP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* BIOS multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/io.h>
|
||||
|
||||
#ifdef MPAPI_PCBIOS
|
||||
#define MPAPI_PREFIX_pcbios
|
||||
#else
|
||||
#define MPAPI_PREFIX_pcbios __pcbios_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Calculate address as seen by a multiprocessor function
|
||||
*
|
||||
* @v address Address in boot processor address space
|
||||
* @ret address Address in application processor address space
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) mp_addr_t
|
||||
MPAPI_INLINE ( pcbios, mp_address ) ( void *address ) {
|
||||
|
||||
return virt_to_phys ( address );
|
||||
}
|
||||
|
||||
#endif /* _IPXE_BIOS_MP_H */
|
||||
223
src/arch/x86/include/ipxe/ucode.h
Normal file
223
src/arch/x86/include/ipxe/ucode.h
Normal file
@ -0,0 +1,223 @@
|
||||
#ifndef _IPXE_UCODE_H
|
||||
#define _IPXE_UCODE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Microcode updates
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/mp.h>
|
||||
|
||||
/** Platform ID MSR */
|
||||
#define MSR_PLATFORM_ID 0x00000017UL
|
||||
|
||||
/** Extract platform ID from MSR value */
|
||||
#define MSR_PLATFORM_ID_VALUE( value ) ( ( (value) >> 50 ) & 0x7 )
|
||||
|
||||
/** Intel microcode load trigger MSR */
|
||||
#define MSR_UCODE_TRIGGER_INTEL 0x00000079UL
|
||||
|
||||
/** AMD microcode load trigger MSR */
|
||||
#define MSR_UCODE_TRIGGER_AMD 0xc0010020UL
|
||||
|
||||
/** CPUID signature applicability mask
|
||||
*
|
||||
* We assume that only steppings may vary between the boot CPU and any
|
||||
* application processors.
|
||||
*/
|
||||
#define UCODE_SIGNATURE_MASK 0xfffffff0UL
|
||||
|
||||
/** Minimum possible microcode version */
|
||||
#define UCODE_VERSION_MIN -0x80000000L
|
||||
|
||||
/** Maximum possible microcode version */
|
||||
#define UCODE_VERSION_MAX 0x7fffffffL
|
||||
|
||||
/** A microcode update control
|
||||
*
|
||||
* This must match the layout as used by the assembly code in
|
||||
* ucode_mp.S.
|
||||
*/
|
||||
struct ucode_control {
|
||||
/** Microcode descriptor list physical address */
|
||||
uint64_t desc;
|
||||
/** Microcode status array physical address */
|
||||
uint64_t status;
|
||||
/** Microcode load trigger MSR */
|
||||
uint32_t trigger_msr;
|
||||
/** Maximum expected APIC ID */
|
||||
uint32_t apic_max;
|
||||
/** Unexpected APIC ID
|
||||
*
|
||||
* Any application processor may set this to indicate that its
|
||||
* APIC ID was higher than the maximum expected APIC ID.
|
||||
*/
|
||||
uint32_t apic_unexpected;
|
||||
/** APIC ID eligibility mask bits */
|
||||
uint32_t apic_mask;
|
||||
/** APIC ID eligibility test bits */
|
||||
uint32_t apic_test;
|
||||
/** Microcode version requires manual clear */
|
||||
uint8_t ver_clear;
|
||||
/** Microcode version is reported via high dword */
|
||||
uint8_t ver_high;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A microcode update descriptor
|
||||
*
|
||||
* This must match the layout as used by the assembly code in
|
||||
* ucode_mp.S.
|
||||
*/
|
||||
struct ucode_descriptor {
|
||||
/** CPUID signature (or 0 to terminate list) */
|
||||
uint32_t signature;
|
||||
/** Microcode version */
|
||||
int32_t version;
|
||||
/** Microcode physical address */
|
||||
uint64_t address;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A microcode update status report
|
||||
*
|
||||
* This must match the layout as used by the assembly code in
|
||||
* ucode_mp.S.
|
||||
*/
|
||||
struct ucode_status {
|
||||
/** CPU signature */
|
||||
uint32_t signature;
|
||||
/** APIC ID (for sanity checking) */
|
||||
uint32_t id;
|
||||
/** Initial microcode version */
|
||||
int32_t before;
|
||||
/** Final microcode version */
|
||||
int32_t after;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A microcode date */
|
||||
struct ucode_date {
|
||||
/** Year (BCD) */
|
||||
uint8_t year;
|
||||
/** Century (BCD) */
|
||||
uint8_t century;
|
||||
/** Day (BCD) */
|
||||
uint8_t day;
|
||||
/** Month (BCD) */
|
||||
uint8_t month;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An Intel microcode update file header */
|
||||
struct intel_ucode_header {
|
||||
/** Header version number */
|
||||
uint32_t hver;
|
||||
/** Microcode version */
|
||||
int32_t version;
|
||||
/** Date */
|
||||
struct ucode_date date;
|
||||
/** CPUID signature */
|
||||
uint32_t signature;
|
||||
/** Checksum */
|
||||
uint32_t checksum;
|
||||
/** Loader version */
|
||||
uint32_t lver;
|
||||
/** Supported platforms */
|
||||
uint32_t platforms;
|
||||
/** Microcode data size (or 0 to indicate 2000 bytes) */
|
||||
uint32_t data_len;
|
||||
/** Total size (or 0 to indicate 2048 bytes) */
|
||||
uint32_t len;
|
||||
/** Reserved */
|
||||
uint8_t reserved[12];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Intel microcode header version number */
|
||||
#define INTEL_UCODE_HVER 0x00000001UL
|
||||
|
||||
/** Intel microcode loader version number */
|
||||
#define INTEL_UCODE_LVER 0x00000001UL
|
||||
|
||||
/** Intel microcode default data length */
|
||||
#define INTEL_UCODE_DATA_LEN 2000
|
||||
|
||||
/** Intel microcode file alignment */
|
||||
#define INTEL_UCODE_ALIGN 1024
|
||||
|
||||
/** An Intel microcode update file extended header */
|
||||
struct intel_ucode_ext_header {
|
||||
/** Extended signature count */
|
||||
uint32_t count;
|
||||
/** Extended checksum */
|
||||
uint32_t checksum;
|
||||
/** Reserved */
|
||||
uint8_t reserved[12];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An Intel microcode extended signature */
|
||||
struct intel_ucode_ext {
|
||||
/** CPUID signature */
|
||||
uint32_t signature;
|
||||
/** Supported platforms */
|
||||
uint32_t platforms;
|
||||
/** Checksum */
|
||||
uint32_t checksum;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An AMD microcode update file header */
|
||||
struct amd_ucode_header {
|
||||
/** Magic signature */
|
||||
uint32_t magic;
|
||||
/** Equivalence table type */
|
||||
uint32_t type;
|
||||
/** Equivalence table length */
|
||||
uint32_t len;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** AMD microcode magic signature */
|
||||
#define AMD_UCODE_MAGIC ( ( 'A' << 16 ) | ( 'M' << 8 ) | ( 'D' << 0 ) )
|
||||
|
||||
/** AMD microcode equivalence table type */
|
||||
#define AMD_UCODE_EQUIV_TYPE 0x00000000UL
|
||||
|
||||
/** An AMD microcode equivalence table entry */
|
||||
struct amd_ucode_equivalence {
|
||||
/** CPU signature */
|
||||
uint32_t signature;
|
||||
/** Reserved */
|
||||
uint8_t reserved_a[8];
|
||||
/** Equivalence ID */
|
||||
uint16_t id;
|
||||
/** Reserved */
|
||||
uint8_t reserved_b[2];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An AMD microcode patch header */
|
||||
struct amd_ucode_patch_header {
|
||||
/** Patch type */
|
||||
uint32_t type;
|
||||
/** Patch length */
|
||||
uint32_t len;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** An AMD microcode patch */
|
||||
struct amd_ucode_patch {
|
||||
/** Date */
|
||||
struct ucode_date date;
|
||||
/** Microcode version */
|
||||
int32_t version;
|
||||
/** Reserved */
|
||||
uint8_t reserved_a[16];
|
||||
/** Equivalence ID */
|
||||
uint16_t id;
|
||||
/** Reserved */
|
||||
uint8_t reserved_b[14];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** AMD patch type */
|
||||
#define AMD_UCODE_PATCH_TYPE 0x00000001UL
|
||||
|
||||
extern mp_func_t ucode_update;
|
||||
|
||||
#endif /* _IPXE_UCODE_H */
|
||||
@ -250,8 +250,10 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
|
||||
/* CODE_DEFAULT: restore default .code32/.code64 directive */
|
||||
#ifdef __x86_64__
|
||||
#define CODE_DEFAULT ".code64"
|
||||
#define STACK_DEFAULT "q"
|
||||
#else
|
||||
#define CODE_DEFAULT ".code32"
|
||||
#define STACK_DEFAULT "l"
|
||||
#endif
|
||||
|
||||
/* LINE_SYMBOL: declare a symbol for the current source code line */
|
||||
@ -268,7 +270,7 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
|
||||
|
||||
/* REAL_CODE: declare a fragment of code that executes in real mode */
|
||||
#define REAL_CODE( asm_code_str ) \
|
||||
"push $1f\n\t" \
|
||||
"push" STACK_DEFAULT " $1f\n\t" \
|
||||
"call real_call\n\t" \
|
||||
TEXT16_CODE ( "\n1:\n\t" \
|
||||
asm_code_str \
|
||||
@ -277,7 +279,7 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
|
||||
|
||||
/* PHYS_CODE: declare a fragment of code that executes in flat physical mode */
|
||||
#define PHYS_CODE( asm_code_str ) \
|
||||
"push $1f\n\t" \
|
||||
"push" STACK_DEFAULT " $1f\n\t" \
|
||||
"call phys_call\n\t" \
|
||||
".section \".text.phys\", \"ax\", @progbits\n\t"\
|
||||
"\n" LINE_SYMBOL "\n\t" \
|
||||
@ -472,6 +474,26 @@ extern struct page_table io_pages;
|
||||
*/
|
||||
#define IO_BASE ( ( void * ) 0x100000000ULL )
|
||||
|
||||
/** Startup IPI real-mode handler */
|
||||
extern char __text16_array ( sipi, [] );
|
||||
#define sipi __use_text16 ( sipi )
|
||||
|
||||
/** Length of startup IPI real-mode handler */
|
||||
extern char sipi_len[];
|
||||
|
||||
/** Startup IPI real-mode handler copy of real-mode data segment */
|
||||
extern uint16_t __text16 ( sipi_ds );
|
||||
#define sipi_ds __use_text16 ( sipi_ds )
|
||||
|
||||
/** Startup IPI protected-mode handler (physical address) */
|
||||
extern uint32_t sipi_handler;
|
||||
|
||||
/** Startup IPI register state */
|
||||
extern struct i386_regs sipi_regs;
|
||||
|
||||
extern void setup_sipi ( unsigned int vector, uint32_t handler,
|
||||
struct i386_regs *regs );
|
||||
|
||||
#endif /* ASSEMBLY */
|
||||
|
||||
#endif /* LIBRM_H */
|
||||
|
||||
@ -46,8 +46,12 @@ static void efix86_cpu_nap ( void ) {
|
||||
* The EFI shell doesn't seem to bother sleeping the CPU; it
|
||||
* just sits there idly burning power.
|
||||
*
|
||||
* If a shutdown is in progess, there may be nothing to
|
||||
* generate an interrupt since the timer is disabled in the
|
||||
* first step of ExitBootServices().
|
||||
*/
|
||||
__asm__ __volatile__ ( "hlt" );
|
||||
if ( ! efi_shutdown_in_progress )
|
||||
__asm__ __volatile__ ( "hlt" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efix86, cpu_nap, efix86_cpu_nap );
|
||||
|
||||
@ -290,29 +290,38 @@ static const char *bios_ansi_input = "";
|
||||
struct bios_key {
|
||||
/** Scancode */
|
||||
uint8_t scancode;
|
||||
/** Key code */
|
||||
uint16_t key;
|
||||
/** Relative key value */
|
||||
uint16_t rkey;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/**
|
||||
* Define a BIOS key mapping
|
||||
*
|
||||
* @v scancode Scancode
|
||||
* @v key iPXE key code
|
||||
* @v bioskey BIOS key mapping
|
||||
*/
|
||||
#define BIOS_KEY( scancode, key ) { scancode, KEY_REL ( key ) }
|
||||
|
||||
/** Mapping from BIOS scan codes to iPXE key codes */
|
||||
static const struct bios_key bios_keys[] = {
|
||||
{ 0x53, KEY_DC },
|
||||
{ 0x48, KEY_UP },
|
||||
{ 0x50, KEY_DOWN },
|
||||
{ 0x4b, KEY_LEFT },
|
||||
{ 0x4d, KEY_RIGHT },
|
||||
{ 0x47, KEY_HOME },
|
||||
{ 0x4f, KEY_END },
|
||||
{ 0x49, KEY_PPAGE },
|
||||
{ 0x51, KEY_NPAGE },
|
||||
{ 0x3f, KEY_F5 },
|
||||
{ 0x40, KEY_F6 },
|
||||
{ 0x41, KEY_F7 },
|
||||
{ 0x42, KEY_F8 },
|
||||
{ 0x43, KEY_F9 },
|
||||
{ 0x44, KEY_F10 },
|
||||
{ 0x85, KEY_F11 },
|
||||
{ 0x86, KEY_F12 },
|
||||
BIOS_KEY ( 0x53, KEY_DC ),
|
||||
BIOS_KEY ( 0x48, KEY_UP ),
|
||||
BIOS_KEY ( 0x50, KEY_DOWN ),
|
||||
BIOS_KEY ( 0x4b, KEY_LEFT ),
|
||||
BIOS_KEY ( 0x4d, KEY_RIGHT ),
|
||||
BIOS_KEY ( 0x47, KEY_HOME ),
|
||||
BIOS_KEY ( 0x4f, KEY_END ),
|
||||
BIOS_KEY ( 0x49, KEY_PPAGE ),
|
||||
BIOS_KEY ( 0x51, KEY_NPAGE ),
|
||||
BIOS_KEY ( 0x3f, KEY_F5 ),
|
||||
BIOS_KEY ( 0x40, KEY_F6 ),
|
||||
BIOS_KEY ( 0x41, KEY_F7 ),
|
||||
BIOS_KEY ( 0x42, KEY_F8 ),
|
||||
BIOS_KEY ( 0x43, KEY_F9 ),
|
||||
BIOS_KEY ( 0x44, KEY_F10 ),
|
||||
BIOS_KEY ( 0x85, KEY_F11 ),
|
||||
BIOS_KEY ( 0x86, KEY_F12 ),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -323,7 +332,7 @@ static const struct bios_key bios_keys[] = {
|
||||
*/
|
||||
static const char * bios_ansi_seq ( unsigned int scancode ) {
|
||||
static char buf[ 5 /* "[" + two digits + terminator + NUL */ ];
|
||||
unsigned int key;
|
||||
unsigned int rkey;
|
||||
unsigned int terminator;
|
||||
unsigned int n;
|
||||
unsigned int i;
|
||||
@ -338,9 +347,9 @@ static const char * bios_ansi_seq ( unsigned int scancode ) {
|
||||
continue;
|
||||
|
||||
/* Construct escape sequence */
|
||||
key = bios_keys[i].key;
|
||||
n = KEY_ANSI_N ( key );
|
||||
terminator = KEY_ANSI_TERMINATOR ( key );
|
||||
rkey = bios_keys[i].rkey;
|
||||
n = KEY_ANSI_N ( rkey );
|
||||
terminator = KEY_ANSI_TERMINATOR ( rkey );
|
||||
*(tmp++) = '[';
|
||||
if ( n )
|
||||
tmp += sprintf ( tmp, "%d", n );
|
||||
@ -479,6 +488,7 @@ struct console_driver bios_console __console_driver = {
|
||||
static __asmcall __used void bios_inject ( struct i386_all_regs *ix86 ) {
|
||||
unsigned int discard_a;
|
||||
unsigned int scancode;
|
||||
unsigned int rkey;
|
||||
unsigned int i;
|
||||
uint16_t keypress;
|
||||
int key;
|
||||
@ -521,9 +531,10 @@ static __asmcall __used void bios_inject ( struct i386_all_regs *ix86 ) {
|
||||
|
||||
/* Handle special keys */
|
||||
if ( key >= KEY_MIN ) {
|
||||
rkey = KEY_REL ( key );
|
||||
for ( i = 0 ; i < ( sizeof ( bios_keys ) /
|
||||
sizeof ( bios_keys[0] ) ) ; i++ ) {
|
||||
if ( bios_keys[i].key == key ) {
|
||||
if ( bios_keys[i].rkey == rkey ) {
|
||||
scancode = bios_keys[i].scancode;
|
||||
keypress = ( scancode << 8 );
|
||||
break;
|
||||
|
||||
173
src/arch/x86/interface/pcbios/bios_mp.c
Normal file
173
src/arch/x86/interface/pcbios/bios_mp.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* BIOS multiprocessor API implementation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <registers.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/msr.h>
|
||||
#include <ipxe/mp.h>
|
||||
|
||||
/** Local APIC base address MSR */
|
||||
#define MSR_APIC_BASE 0x0000001b
|
||||
|
||||
/** Local APIC is in x2APIC mode */
|
||||
#define MSR_APIC_BASE_X2APIC 0x400
|
||||
|
||||
/** Local APIC base address mask */
|
||||
#define MSR_APIC_BASE_MASK ( ~0xfffULL )
|
||||
|
||||
/** Interrupt command register */
|
||||
#define APIC_ICR 0x0300
|
||||
|
||||
/** Interrupt command register (x2APIC) */
|
||||
#define MSR_X2APIC_ICR 0x830
|
||||
|
||||
/** Interrupt command register: send to all excluding self */
|
||||
#define APIC_ICR_ALL_NOT_SELF 0x000c0000
|
||||
|
||||
/** Interrupt command register: level mode */
|
||||
#define APIC_ICR_LEVEL 0x00008000
|
||||
|
||||
/** Interrupt command register: level asserted */
|
||||
#define APIC_ICR_LEVEL_ASSERT 0x00004000
|
||||
|
||||
/** Interrupt command register: INIT */
|
||||
#define APIC_ICR_INIT 0x00000500
|
||||
|
||||
/** Interrupt command register: SIPI */
|
||||
#define APIC_ICR_SIPI( vector ) ( 0x00000600 | (vector) )
|
||||
|
||||
/** Time to wait for an IPI to complete */
|
||||
#define IPI_WAIT_MS 10
|
||||
|
||||
/**
|
||||
* Startup IPI vector
|
||||
*
|
||||
* The real-mode startup IPI code must be copied to a page boundary in
|
||||
* base memory. We fairly arbitrarily choose to place this at 0x8000.
|
||||
*/
|
||||
#define SIPI_VECTOR 0x08
|
||||
|
||||
/** Protected-mode startup IPI handler */
|
||||
extern void __asmcall mp_jump ( mp_addr_t func, mp_addr_t opaque );
|
||||
|
||||
/**
|
||||
* Execute a multiprocessor function on the boot processor
|
||||
*
|
||||
* @v func Multiprocessor function
|
||||
* @v opaque Opaque data pointer
|
||||
*/
|
||||
static void bios_mp_exec_boot ( mp_func_t func, void *opaque ) {
|
||||
|
||||
/* Call multiprocessor function with physical addressing */
|
||||
__asm__ __volatile__ ( PHYS_CODE ( "pushl %k2\n\t"
|
||||
"pushl %k1\n\t"
|
||||
"call *%k0\n\t"
|
||||
"addl $8, %%esp\n\t" )
|
||||
: : "r" ( mp_address ( mp_call ) ),
|
||||
"r" ( mp_address ( func ) ),
|
||||
"r" ( mp_address ( opaque ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an interprocessor interrupt
|
||||
*
|
||||
* @v apic APIC base address
|
||||
* @v x2apic x2APIC mode enabled
|
||||
* @v icr Interrupt control register value
|
||||
*/
|
||||
static void bios_mp_ipi ( void *apic, int x2apic, uint32_t icr ) {
|
||||
|
||||
/* Write ICR according to APIC/x2APIC mode */
|
||||
DBGC ( MSR_APIC_BASE, "BIOSMP sending IPI %#08x\n", icr );
|
||||
if ( x2apic ) {
|
||||
wrmsr ( MSR_X2APIC_ICR, icr );
|
||||
} else {
|
||||
writel ( icr, ( apic + APIC_ICR ) );
|
||||
}
|
||||
|
||||
/* Allow plenty of time for delivery to complete */
|
||||
mdelay ( IPI_WAIT_MS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a multiprocessor function on all application processors
|
||||
*
|
||||
* @v func Multiprocessor function
|
||||
* @v opaque Opaque data pointer
|
||||
*/
|
||||
static void bios_mp_start_all ( mp_func_t func, void *opaque ) {
|
||||
struct i386_regs regs;
|
||||
uint64_t base;
|
||||
uint32_t ipi;
|
||||
void *apic;
|
||||
int x2apic;
|
||||
|
||||
/* Prepare SIPI handler */
|
||||
regs.eax = mp_address ( func );
|
||||
regs.edx = mp_address ( opaque );
|
||||
setup_sipi ( SIPI_VECTOR, virt_to_phys ( mp_jump ), ®s );
|
||||
|
||||
/* Get local APIC base address and mode */
|
||||
base = rdmsr ( MSR_APIC_BASE );
|
||||
x2apic = ( base & MSR_APIC_BASE_X2APIC );
|
||||
DBGC ( MSR_APIC_BASE, "BIOSMP local %sAPIC base %#llx\n",
|
||||
( x2apic ? "x2" : "" ), ( ( unsigned long long ) base ) );
|
||||
|
||||
/* Map local APIC */
|
||||
apic = ioremap ( ( base & MSR_APIC_BASE_MASK ), PAGE_SIZE );
|
||||
if ( ! apic )
|
||||
goto err_ioremap;
|
||||
|
||||
/* Assert INIT IPI */
|
||||
ipi = ( APIC_ICR_ALL_NOT_SELF | APIC_ICR_LEVEL |
|
||||
APIC_ICR_LEVEL_ASSERT | APIC_ICR_INIT );
|
||||
bios_mp_ipi ( apic, x2apic, ipi );
|
||||
|
||||
/* Clear INIT IPI */
|
||||
ipi &= ~APIC_ICR_LEVEL_ASSERT;
|
||||
bios_mp_ipi ( apic, x2apic, ipi );
|
||||
|
||||
/* Send SIPI */
|
||||
ipi = ( APIC_ICR_ALL_NOT_SELF | APIC_ICR_SIPI ( SIPI_VECTOR ) );
|
||||
bios_mp_ipi ( apic, x2apic, ipi );
|
||||
|
||||
iounmap ( apic );
|
||||
err_ioremap:
|
||||
/* No way to handle errors: caller must check that
|
||||
* multiprocessor function executed as expected.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
PROVIDE_MPAPI_INLINE ( pcbios, mp_address );
|
||||
PROVIDE_MPAPI ( pcbios, mp_exec_boot, bios_mp_exec_boot );
|
||||
PROVIDE_MPAPI ( pcbios, mp_start_all, bios_mp_start_all );
|
||||
@ -44,11 +44,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* @v smbios SMBIOS entry point descriptor structure to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bios_find_smbios ( struct smbios *smbios ) {
|
||||
static int bios_find_smbios2 ( struct smbios *smbios ) {
|
||||
struct smbios_entry entry;
|
||||
int rc;
|
||||
|
||||
/* Scan through BIOS segment to find SMBIOS entry point */
|
||||
/* Scan through BIOS segment to find SMBIOS 32-bit entry point */
|
||||
if ( ( rc = find_smbios_entry ( real_to_user ( BIOS_SEG, 0 ), 0x10000,
|
||||
&entry ) ) != 0 )
|
||||
return rc;
|
||||
@ -62,4 +62,55 @@ static int bios_find_smbios ( struct smbios *smbios ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find SMBIOS
|
||||
*
|
||||
* @v smbios SMBIOS entry point descriptor structure to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bios_find_smbios3 ( struct smbios *smbios ) {
|
||||
struct smbios3_entry entry;
|
||||
int rc;
|
||||
|
||||
/* Scan through BIOS segment to find SMBIOS 64-bit entry point */
|
||||
if ( ( rc = find_smbios3_entry ( real_to_user ( BIOS_SEG, 0 ), 0x10000,
|
||||
&entry ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Check that address is accessible */
|
||||
if ( entry.smbios_address > ~( ( physaddr_t ) 0 ) ) {
|
||||
DBG ( "SMBIOS3 at %08llx is inaccessible\n",
|
||||
( ( unsigned long long ) entry.smbios_address ) );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Fill in entry point descriptor structure */
|
||||
smbios->address = phys_to_user ( entry.smbios_address );
|
||||
smbios->len = entry.smbios_len;
|
||||
smbios->count = 0;
|
||||
smbios->version = SMBIOS_VERSION ( entry.major, entry.minor );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find SMBIOS
|
||||
*
|
||||
* @v smbios SMBIOS entry point descriptor structure to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int bios_find_smbios ( struct smbios *smbios ) {
|
||||
int rc;
|
||||
|
||||
/* Use 32-bit table if present */
|
||||
if ( ( rc = bios_find_smbios2 ( smbios ) ) == 0 )
|
||||
return 0;
|
||||
|
||||
/* Otherwise, use 64-bit table if present and accessible */
|
||||
if ( ( rc = bios_find_smbios3 ( smbios ) ) == 0 )
|
||||
return 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
PROVIDE_SMBIOS ( pcbios, find_smbios, bios_find_smbios );
|
||||
|
||||
@ -23,9 +23,9 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
#define SMAP 0x534d4150
|
||||
|
||||
|
||||
@ -183,8 +183,8 @@ static int int13_parse_eltorito ( struct san_device *sandev, void *scratch ) {
|
||||
/* Read boot record volume descriptor */
|
||||
if ( ( rc = sandev_read ( sandev, ELTORITO_LBA, 1,
|
||||
virt_to_user ( boot ) ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not read El Torito boot "
|
||||
"record volume descriptor: %s\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not read El "
|
||||
"Torito boot record volume descriptor: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
@ -192,10 +192,11 @@ static int int13_parse_eltorito ( struct san_device *sandev, void *scratch ) {
|
||||
/* Check for an El Torito boot catalog */
|
||||
if ( memcmp ( boot, &boot_check, sizeof ( boot_check ) ) == 0 ) {
|
||||
int13->boot_catalog = boot->sector;
|
||||
DBGC ( sandev, "INT13 drive %02x has an El Torito boot catalog "
|
||||
"at LBA %08x\n", sandev->drive, int13->boot_catalog );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has an El Torito boot "
|
||||
"catalog at LBA %08x\n", sandev->drive,
|
||||
int13->boot_catalog );
|
||||
} else {
|
||||
DBGC ( sandev, "INT13 drive %02x has no El Torito boot "
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has no El Torito boot "
|
||||
"catalog\n", sandev->drive );
|
||||
}
|
||||
|
||||
@ -228,14 +229,14 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
|
||||
|
||||
/* Read partition table */
|
||||
if ( ( rc = sandev_read ( sandev, 0, 1, virt_to_user ( mbr ) ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not read "
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not read "
|
||||
"partition table to guess geometry: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
DBGC2 ( sandev, "INT13 drive %02x has MBR:\n", sandev->drive );
|
||||
DBGC2_HDA ( sandev, 0, mbr, sizeof ( *mbr ) );
|
||||
DBGC ( sandev, "INT13 drive %02x has signature %08x\n",
|
||||
DBGC2 ( sandev->drive, "INT13 drive %02x has MBR:\n", sandev->drive );
|
||||
DBGC2_HDA ( sandev->drive, 0, mbr, sizeof ( *mbr ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has signature %08x\n",
|
||||
sandev->drive, mbr->signature );
|
||||
|
||||
/* Scan through partition table and modify guesses for
|
||||
@ -260,8 +261,8 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
|
||||
if ( ( start_cylinder == 0 ) && ( start_head != 0 ) ) {
|
||||
*sectors = ( ( partition->start + 1 - start_sector ) /
|
||||
start_head );
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"xx/xx/%d based on partition %d\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S xx/xx/%d based on partition %d\n",
|
||||
sandev->drive, *sectors, ( i + 1 ) );
|
||||
}
|
||||
|
||||
@ -272,14 +273,14 @@ static int int13_guess_geometry_hdd ( struct san_device *sandev, void *scratch,
|
||||
end_sector = PART_SECTOR ( partition->chs_end );
|
||||
if ( ( end_head + 1 ) > *heads ) {
|
||||
*heads = ( end_head + 1 );
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"xx/%d/xx based on partition %d\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S xx/%d/xx based on partition %d\n",
|
||||
sandev->drive, *heads, ( i + 1 ) );
|
||||
}
|
||||
if ( end_sector > *sectors ) {
|
||||
*sectors = end_sector;
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"xx/xx/%d based on partition %d\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S xx/xx/%d based on partition %d\n",
|
||||
sandev->drive, *sectors, ( i + 1 ) );
|
||||
}
|
||||
}
|
||||
@ -343,9 +344,10 @@ static int int13_guess_geometry_fdd ( struct san_device *sandev,
|
||||
*heads = INT13_FDD_HEADS ( geometry );
|
||||
*sectors = INT13_FDD_SECTORS ( geometry );
|
||||
if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) {
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S "
|
||||
"%d/%d/%d based on size %dK\n", sandev->drive,
|
||||
cylinders, *heads, *sectors, ( blocks / 2 ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing "
|
||||
"C/H/S %d/%d/%d based on size %dK\n",
|
||||
sandev->drive, cylinders, *heads, *sectors,
|
||||
( blocks / 2 ) );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -355,8 +357,9 @@ static int int13_guess_geometry_fdd ( struct san_device *sandev,
|
||||
*/
|
||||
*heads = 2;
|
||||
*sectors = 18;
|
||||
DBGC ( sandev, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
|
||||
"%dK\n", sandev->drive, *heads, *sectors, ( blocks / 2 ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x guessing C/H/S xx/%d/%d "
|
||||
"based on size %dK\n", sandev->drive, *heads, *sectors,
|
||||
( blocks / 2 ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -431,8 +434,8 @@ static void int13_sync_num_drives ( void ) {
|
||||
required = ( ( max_drive & 0x7f ) + 1 );
|
||||
if ( *counter < required ) {
|
||||
*counter = required;
|
||||
DBGC ( sandev, "INT13 drive %02x added to drive count: "
|
||||
"%d HDDs, %d FDDs\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x added to "
|
||||
"drive count: %d HDDs, %d FDDs\n",
|
||||
sandev->drive, num_drives, num_fdds );
|
||||
}
|
||||
}
|
||||
@ -472,7 +475,7 @@ static int int13_reset ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 __unused ) {
|
||||
int rc;
|
||||
|
||||
DBGC2 ( sandev, "Reset drive\n" );
|
||||
DBGC2 ( sandev->drive, "Reset drive\n" );
|
||||
|
||||
/* Reset SAN device */
|
||||
if ( ( rc = sandev_reset ( sandev ) ) != 0 )
|
||||
@ -491,7 +494,7 @@ static int int13_get_last_status ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 __unused ) {
|
||||
struct int13_data *int13 = sandev->priv;
|
||||
|
||||
DBGC2 ( sandev, "Get status of last operation\n" );
|
||||
DBGC2 ( sandev->drive, "Get status of last operation\n" );
|
||||
return int13->last_status;
|
||||
}
|
||||
|
||||
@ -524,8 +527,8 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
|
||||
/* Validate blocksize */
|
||||
if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) {
|
||||
DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) "
|
||||
"for non-extended read/write\n",
|
||||
DBGC ( sandev->drive, "\nINT 13 drive %02x invalid blocksize "
|
||||
"(%zd) for non-extended read/write\n",
|
||||
sandev->drive, sandev_blksize ( sandev ) );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -537,9 +540,10 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
if ( ( cylinder >= int13->cylinders ) ||
|
||||
( head >= int13->heads ) ||
|
||||
( sector < 1 ) || ( sector > int13->sectors_per_track ) ) {
|
||||
DBGC ( sandev, "C/H/S %d/%d/%d out of range for geometry "
|
||||
"%d/%d/%d\n", cylinder, head, sector, int13->cylinders,
|
||||
int13->heads, int13->sectors_per_track );
|
||||
DBGC ( sandev->drive, "C/H/S %d/%d/%d out of range for "
|
||||
"geometry %d/%d/%d\n", cylinder, head, sector,
|
||||
int13->cylinders, int13->heads,
|
||||
int13->sectors_per_track );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
lba = ( ( ( ( cylinder * int13->heads ) + head )
|
||||
@ -547,13 +551,13 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
count = ix86->regs.al;
|
||||
buffer = real_to_user ( ix86->segs.es, ix86->regs.bx );
|
||||
|
||||
DBGC2 ( sandev, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x (count %d)\n",
|
||||
cylinder, head, sector, lba, ix86->segs.es, ix86->regs.bx,
|
||||
count );
|
||||
DBGC2 ( sandev->drive, "C/H/S %d/%d/%d = LBA %08lx <-> %04x:%04x "
|
||||
"(count %d)\n", cylinder, head, sector, lba, ix86->segs.es,
|
||||
ix86->regs.bx, count );
|
||||
|
||||
/* Read from / write to block device */
|
||||
if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ){
|
||||
DBGC ( sandev, "INT13 drive %02x I/O failed: %s\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x I/O failed: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
return -INT13_STATUS_READ_ERROR;
|
||||
}
|
||||
@ -577,7 +581,7 @@ static int int13_rw_sectors ( struct san_device *sandev,
|
||||
static int int13_read_sectors ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Read: " );
|
||||
DBGC2 ( sandev->drive, "Read: " );
|
||||
return int13_rw_sectors ( sandev, ix86, sandev_read );
|
||||
}
|
||||
|
||||
@ -597,7 +601,7 @@ static int int13_read_sectors ( struct san_device *sandev,
|
||||
static int int13_write_sectors ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Write: " );
|
||||
DBGC2 ( sandev->drive, "Write: " );
|
||||
return int13_rw_sectors ( sandev, ix86, sandev_write );
|
||||
}
|
||||
|
||||
@ -619,12 +623,12 @@ static int int13_get_parameters ( struct san_device *sandev,
|
||||
unsigned int max_head = int13->heads - 1;
|
||||
unsigned int max_sector = int13->sectors_per_track; /* sic */
|
||||
|
||||
DBGC2 ( sandev, "Get drive parameters\n" );
|
||||
DBGC2 ( sandev->drive, "Get drive parameters\n" );
|
||||
|
||||
/* Validate blocksize */
|
||||
if ( sandev_blksize ( sandev ) != INT13_BLKSIZE ) {
|
||||
DBGC ( sandev, "\nINT 13 drive %02x invalid blocksize (%zd) "
|
||||
"for non-extended parameters\n",
|
||||
DBGC ( sandev->drive, "\nINT 13 drive %02x invalid blocksize "
|
||||
"(%zd) for non-extended parameters\n",
|
||||
sandev->drive, sandev_blksize ( sandev ) );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -657,7 +661,7 @@ static int int13_get_disk_type ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
uint32_t blocks;
|
||||
|
||||
DBGC2 ( sandev, "Get disk type\n" );
|
||||
DBGC2 ( sandev->drive, "Get disk type\n" );
|
||||
|
||||
if ( int13_is_fdd ( sandev ) ) {
|
||||
return INT13_DISK_TYPE_FDD;
|
||||
@ -682,7 +686,7 @@ static int int13_extension_check ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
if ( ( ix86->regs.bx == 0x55aa ) && ! int13_is_fdd ( sandev ) ) {
|
||||
DBGC2 ( sandev, "INT13 extensions installation check\n" );
|
||||
DBGC2 ( sandev->drive, "INT13 extensions check\n" );
|
||||
ix86->regs.bx = 0xaa55;
|
||||
ix86->regs.cx = ( INT13_EXTENSION_LINEAR |
|
||||
INT13_EXTENSION_EDD |
|
||||
@ -725,7 +729,8 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
get_real ( bufsize, ix86->segs.ds,
|
||||
( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
|
||||
if ( bufsize < offsetof ( typeof ( addr ), buffer_phys ) ) {
|
||||
DBGC2 ( sandev, "<invalid buffer size %#02x\n>\n", bufsize );
|
||||
DBGC2 ( sandev->drive, "<invalid buffer size %#02x\n>\n",
|
||||
bufsize );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
|
||||
@ -733,17 +738,18 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
memset ( &addr, 0, sizeof ( addr ) );
|
||||
copy_from_real ( &addr, ix86->segs.ds, ix86->regs.si, bufsize );
|
||||
lba = addr.lba;
|
||||
DBGC2 ( sandev, "LBA %08llx <-> ", ( ( unsigned long long ) lba ) );
|
||||
DBGC2 ( sandev->drive, "LBA %08llx <-> ",
|
||||
( ( unsigned long long ) lba ) );
|
||||
if ( ( addr.count == 0xff ) ||
|
||||
( ( addr.buffer.segment == 0xffff ) &&
|
||||
( addr.buffer.offset == 0xffff ) ) ) {
|
||||
buffer = phys_to_user ( addr.buffer_phys );
|
||||
DBGC2 ( sandev, "%08llx",
|
||||
DBGC2 ( sandev->drive, "%08llx",
|
||||
( ( unsigned long long ) addr.buffer_phys ) );
|
||||
} else {
|
||||
buffer = real_to_user ( addr.buffer.segment,
|
||||
addr.buffer.offset );
|
||||
DBGC2 ( sandev, "%04x:%04x", addr.buffer.segment,
|
||||
DBGC2 ( sandev->drive, "%04x:%04x", addr.buffer.segment,
|
||||
addr.buffer.offset );
|
||||
}
|
||||
if ( addr.count <= 0x7f ) {
|
||||
@ -751,15 +757,15 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
} else if ( addr.count == 0xff ) {
|
||||
count = addr.long_count;
|
||||
} else {
|
||||
DBGC2 ( sandev, " <invalid count %#02x>\n", addr.count );
|
||||
DBGC2 ( sandev->drive, " <invalid count %#02x>\n", addr.count );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
DBGC2 ( sandev, " (count %ld)\n", count );
|
||||
DBGC2 ( sandev->drive, " (count %ld)\n", count );
|
||||
|
||||
/* Read from / write to block device */
|
||||
if ( ( rc = sandev_rw ( sandev, lba, count, buffer ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x extended I/O failed: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x extended I/O failed: "
|
||||
"%s\n", sandev->drive, strerror ( rc ) );
|
||||
/* Record that no blocks were transferred successfully */
|
||||
addr.count = 0;
|
||||
put_real ( addr.count, ix86->segs.ds,
|
||||
@ -781,7 +787,7 @@ static int int13_extended_rw ( struct san_device *sandev,
|
||||
static int int13_extended_read ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Extended read: " );
|
||||
DBGC2 ( sandev->drive, "Extended read: " );
|
||||
return int13_extended_rw ( sandev, ix86, sandev_read );
|
||||
}
|
||||
|
||||
@ -795,7 +801,7 @@ static int int13_extended_read ( struct san_device *sandev,
|
||||
static int int13_extended_write ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
|
||||
DBGC2 ( sandev, "Extended write: " );
|
||||
DBGC2 ( sandev->drive, "Extended write: " );
|
||||
return int13_extended_rw ( sandev, ix86, sandev_write );
|
||||
}
|
||||
|
||||
@ -818,7 +824,7 @@ static int int13_extended_verify ( struct san_device *sandev,
|
||||
sizeof ( addr ));
|
||||
lba = addr.lba;
|
||||
count = addr.count;
|
||||
DBGC2 ( sandev, "Verify: LBA %08llx (count %ld)\n",
|
||||
DBGC2 ( sandev->drive, "Verify: LBA %08llx (count %ld)\n",
|
||||
( ( unsigned long long ) lba ), count );
|
||||
}
|
||||
|
||||
@ -845,7 +851,7 @@ static int int13_extended_seek ( struct san_device *sandev,
|
||||
sizeof ( addr ));
|
||||
lba = addr.lba;
|
||||
count = addr.count;
|
||||
DBGC2 ( sandev, "Seek: LBA %08llx (count %ld)\n",
|
||||
DBGC2 ( sandev->drive, "Seek: LBA %08llx (count %ld)\n",
|
||||
( ( unsigned long long ) lba ), count );
|
||||
}
|
||||
|
||||
@ -879,8 +885,8 @@ static int int13_device_path_info ( struct san_device *sandev,
|
||||
/* Get underlying hardware device */
|
||||
device = identify_device ( &sanpath->block );
|
||||
if ( ! device ) {
|
||||
DBGC ( sandev, "INT13 drive %02x cannot identify hardware "
|
||||
"device\n", sandev->drive );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x cannot identify "
|
||||
"hardware device\n", sandev->drive );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -895,16 +901,16 @@ static int int13_device_path_info ( struct san_device *sandev,
|
||||
dpi->interface_path.pci.channel = 0xff; /* unused */
|
||||
break;
|
||||
default:
|
||||
DBGC ( sandev, "INT13 drive %02x unrecognised bus type %d\n",
|
||||
sandev->drive, desc->bus_type );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x unrecognised bus "
|
||||
"type %d\n", sandev->drive, desc->bus_type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Get EDD block device description */
|
||||
if ( ( rc = edd_describe ( &sanpath->block, &dpi->interface_type,
|
||||
&dpi->device_path ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x cannot identify block device: "
|
||||
"%s\n", sandev->drive, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x cannot identify "
|
||||
"block device: %s\n", sandev->drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -938,8 +944,8 @@ static int int13_get_extended_parameters ( struct san_device *sandev,
|
||||
get_real ( bufsize, ix86->segs.ds,
|
||||
( ix86->regs.si + offsetof ( typeof ( params ), bufsize )));
|
||||
|
||||
DBGC2 ( sandev, "Get extended drive parameters to %04x:%04x+%02x\n",
|
||||
ix86->segs.ds, ix86->regs.si, bufsize );
|
||||
DBGC2 ( sandev->drive, "Get extended drive parameters to "
|
||||
"%04x:%04x+%02x\n", ix86->segs.ds, ix86->regs.si, bufsize );
|
||||
|
||||
/* Build drive parameters */
|
||||
memset ( ¶ms, 0, sizeof ( params ) );
|
||||
@ -955,8 +961,8 @@ static int int13_get_extended_parameters ( struct san_device *sandev,
|
||||
params.sector_size = sandev_blksize ( sandev );
|
||||
memset ( ¶ms.dpte, 0xff, sizeof ( params.dpte ) );
|
||||
if ( ( rc = int13_device_path_info ( sandev, ¶ms.dpi ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not provide device "
|
||||
"path information: %s\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not provide "
|
||||
"device path information: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
len = offsetof ( typeof ( params ), dpi );
|
||||
}
|
||||
@ -973,11 +979,11 @@ static int int13_get_extended_parameters ( struct san_device *sandev,
|
||||
params.bufsize = offsetof ( typeof ( params ), dpi );
|
||||
}
|
||||
|
||||
DBGC ( sandev, "INT 13 drive %02x described using extended "
|
||||
DBGC ( sandev->drive, "INT 13 drive %02x described using extended "
|
||||
"parameters:\n", sandev->drive );
|
||||
address.segment = ix86->segs.ds;
|
||||
address.offset = ix86->regs.si;
|
||||
DBGC_HDA ( sandev, address, ¶ms, len );
|
||||
DBGC_HDA ( sandev->drive, address, ¶ms, len );
|
||||
|
||||
/* Return drive parameters */
|
||||
if ( len > bufsize )
|
||||
@ -998,13 +1004,13 @@ static int int13_cdrom_status_terminate ( struct san_device *sandev,
|
||||
struct i386_all_regs *ix86 ) {
|
||||
struct int13_cdrom_specification specification;
|
||||
|
||||
DBGC2 ( sandev, "Get CD-ROM emulation status to %04x:%04x%s\n",
|
||||
DBGC2 ( sandev->drive, "Get CD-ROM emulation status to %04x:%04x%s\n",
|
||||
ix86->segs.ds, ix86->regs.si,
|
||||
( ix86->regs.al ? "" : " and terminate" ) );
|
||||
|
||||
/* Fail if we are not a CD-ROM */
|
||||
if ( ! sandev->is_cdrom ) {
|
||||
DBGC ( sandev, "INT13 drive %02x is not a CD-ROM\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x is not a CD-ROM\n",
|
||||
sandev->drive );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -1039,11 +1045,12 @@ static int int13_cdrom_read_boot_catalog ( struct san_device *sandev,
|
||||
/* Read parameters from command packet */
|
||||
copy_from_real ( &command, ix86->segs.ds, ix86->regs.si,
|
||||
sizeof ( command ) );
|
||||
DBGC2 ( sandev, "Read CD-ROM boot catalog to %08x\n", command.buffer );
|
||||
DBGC2 ( sandev->drive, "Read CD-ROM boot catalog to %08x\n",
|
||||
command.buffer );
|
||||
|
||||
/* Fail if we have no boot catalog */
|
||||
if ( ! int13->boot_catalog ) {
|
||||
DBGC ( sandev, "INT13 drive %02x has no boot catalog\n",
|
||||
DBGC ( sandev->drive, "INT13 drive %02x has no boot catalog\n",
|
||||
sandev->drive );
|
||||
return -INT13_STATUS_INVALID;
|
||||
}
|
||||
@ -1052,8 +1059,8 @@ static int int13_cdrom_read_boot_catalog ( struct san_device *sandev,
|
||||
/* Read from boot catalog */
|
||||
if ( ( rc = sandev_read ( sandev, start, command.count,
|
||||
phys_to_user ( command.buffer ) ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not read boot catalog: "
|
||||
"%s\n", sandev->drive, strerror ( rc ) );
|
||||
DBGC ( sandev->drive, "INT13 drive %02x could not read boot "
|
||||
"catalog: %s\n", sandev->drive, strerror ( rc ) );
|
||||
return -INT13_STATUS_READ_ERROR;
|
||||
}
|
||||
|
||||
@ -1080,8 +1087,8 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
if ( bios_drive != sandev->drive ) {
|
||||
/* Remap any accesses to this drive's natural number */
|
||||
if ( bios_drive == int13->natural_drive ) {
|
||||
DBGC2 ( sandev, "INT13,%02x (%02x) remapped to "
|
||||
"(%02x)\n", ix86->regs.ah,
|
||||
DBGC2 ( sandev->drive, "INT13,%02x (%02x) "
|
||||
"remapped to (%02x)\n", ix86->regs.ah,
|
||||
bios_drive, sandev->drive );
|
||||
ix86->regs.dl = sandev->drive;
|
||||
return;
|
||||
@ -1094,7 +1101,7 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
}
|
||||
}
|
||||
|
||||
DBGC2 ( sandev, "INT13,%02x (%02x): ",
|
||||
DBGC2 ( sandev->drive, "INT13,%02x (%02x): ",
|
||||
ix86->regs.ah, bios_drive );
|
||||
|
||||
switch ( command ) {
|
||||
@ -1141,7 +1148,7 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
status = int13_cdrom_read_boot_catalog ( sandev, ix86 );
|
||||
break;
|
||||
default:
|
||||
DBGC2 ( sandev, "*** Unrecognised INT13 ***\n" );
|
||||
DBGC2 ( sandev->drive, "*** Unrecognised INT13 ***\n" );
|
||||
status = -INT13_STATUS_INVALID;
|
||||
break;
|
||||
}
|
||||
@ -1152,8 +1159,9 @@ static __asmcall __used void int13 ( struct i386_all_regs *ix86 ) {
|
||||
/* Negative status indicates an error */
|
||||
if ( status < 0 ) {
|
||||
status = -status;
|
||||
DBGC ( sandev, "INT13,%02x (%02x) failed with status "
|
||||
"%02x\n", ix86->regs.ah, sandev->drive, status );
|
||||
DBGC ( sandev->drive, "INT13,%02x (%02x) failed with "
|
||||
"status %02x\n", ix86->regs.ah, sandev->drive,
|
||||
status );
|
||||
} else {
|
||||
ix86->flags &= ~CF;
|
||||
}
|
||||
@ -1269,7 +1277,7 @@ static int int13_hook ( unsigned int drive, struct uri **uris,
|
||||
|
||||
/* Register SAN device */
|
||||
if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
|
||||
DBGC ( sandev, "INT13 drive %02x could not register: %s\n",
|
||||
DBGC ( drive, "INT13 drive %02x could not register: %s\n",
|
||||
drive, strerror ( rc ) );
|
||||
goto err_register;
|
||||
}
|
||||
@ -1289,10 +1297,9 @@ static int int13_hook ( unsigned int drive, struct uri **uris,
|
||||
( ( rc = int13_guess_geometry ( sandev, scratch ) ) != 0 ) )
|
||||
goto err_guess_geometry;
|
||||
|
||||
DBGC ( sandev, "INT13 drive %02x (naturally %02x) registered with "
|
||||
"C/H/S geometry %d/%d/%d\n",
|
||||
sandev->drive, int13->natural_drive, int13->cylinders,
|
||||
int13->heads, int13->sectors_per_track );
|
||||
DBGC ( drive, "INT13 drive %02x (naturally %02x) registered with "
|
||||
"C/H/S geometry %d/%d/%d\n", drive, int13->natural_drive,
|
||||
int13->cylinders, int13->heads, int13->sectors_per_track );
|
||||
|
||||
/* Hook INT 13 vector if not already hooked */
|
||||
if ( need_hook ) {
|
||||
@ -1332,7 +1339,7 @@ static void int13_unhook ( unsigned int drive ) {
|
||||
/* Find drive */
|
||||
sandev = sandev_find ( drive );
|
||||
if ( ! sandev ) {
|
||||
DBG ( "INT13 cannot find drive %02x\n", drive );
|
||||
DBGC ( drive, "INT13 drive %02x is not a SAN drive\n", drive );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1343,7 +1350,7 @@ static void int13_unhook ( unsigned int drive ) {
|
||||
* to do so reliably.
|
||||
*/
|
||||
|
||||
DBGC ( sandev, "INT13 drive %02x unregistered\n", sandev->drive );
|
||||
DBGC ( drive, "INT13 drive %02x unregistered\n", drive );
|
||||
|
||||
/* Unhook INT 13 vector if no more drives */
|
||||
if ( ! have_sandevs() ) {
|
||||
@ -1387,8 +1394,8 @@ static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
|
||||
: "a" ( 0x0201 ), "b" ( *address ),
|
||||
"c" ( 1 ), "d" ( drive ) );
|
||||
if ( status ) {
|
||||
DBG ( "INT13 drive %02x could not read MBR (status %04x)\n",
|
||||
drive, status );
|
||||
DBGC ( drive, "INT13 drive %02x could not read MBR (status "
|
||||
"%04x)\n", drive, status );
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1397,8 +1404,8 @@ static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
|
||||
( address->offset +
|
||||
offsetof ( struct master_boot_record, magic ) ) );
|
||||
if ( magic != INT13_MBR_MAGIC ) {
|
||||
DBG ( "INT13 drive %02x does not contain a valid MBR\n",
|
||||
drive );
|
||||
DBGC ( drive, "INT13 drive %02x does not contain a valid MBR\n",
|
||||
drive );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
@ -1444,8 +1451,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
: "a" ( 0x4d00 ), "d" ( drive ),
|
||||
"S" ( __from_data16 ( &eltorito_cmd ) ) );
|
||||
if ( status ) {
|
||||
DBG ( "INT13 drive %02x could not read El Torito boot catalog "
|
||||
"(status %04x)\n", drive, status );
|
||||
DBGC ( drive, "INT13 drive %02x could not read El Torito boot "
|
||||
"catalog (status %04x)\n", drive, status );
|
||||
return -EIO;
|
||||
}
|
||||
copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0,
|
||||
@ -1453,26 +1460,27 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
|
||||
/* Sanity checks */
|
||||
if ( catalog.valid.platform_id != ELTORITO_PLATFORM_X86 ) {
|
||||
DBG ( "INT13 drive %02x El Torito specifies unknown platform "
|
||||
"%02x\n", drive, catalog.valid.platform_id );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito specifies unknown "
|
||||
"platform %02x\n", drive, catalog.valid.platform_id );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if ( catalog.boot.indicator != ELTORITO_BOOTABLE ) {
|
||||
DBG ( "INT13 drive %02x El Torito is not bootable\n", drive );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito is not bootable\n",
|
||||
drive );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
if ( catalog.boot.media_type != ELTORITO_NO_EMULATION ) {
|
||||
DBG ( "INT13 drive %02x El Torito requires emulation "
|
||||
DBGC ( drive, "INT13 drive %02x El Torito requires emulation "
|
||||
"type %02x\n", drive, catalog.boot.media_type );
|
||||
return -ENOTSUP;
|
||||
}
|
||||
DBG ( "INT13 drive %02x El Torito boot image at LBA %08x (count %d)\n",
|
||||
drive, catalog.boot.start, catalog.boot.length );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito boot image at LBA %08x "
|
||||
"(count %d)\n", drive, catalog.boot.start, catalog.boot.length );
|
||||
address->segment = ( catalog.boot.load_segment ?
|
||||
catalog.boot.load_segment : 0x7c0 );
|
||||
address->offset = 0;
|
||||
DBG ( "INT13 drive %02x El Torito boot image loads at %04x:%04x\n",
|
||||
drive, address->segment, address->offset );
|
||||
DBGC ( drive, "INT13 drive %02x El Torito boot image loads at "
|
||||
"%04x:%04x\n", drive, address->segment, address->offset );
|
||||
|
||||
/* Use INT 13, 42 to read the boot image */
|
||||
eltorito_address.bufsize =
|
||||
@ -1491,8 +1499,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
: "a" ( 0x4200 ), "d" ( drive ),
|
||||
"S" ( __from_data16 ( &eltorito_address ) ) );
|
||||
if ( status ) {
|
||||
DBG ( "INT13 drive %02x could not read El Torito boot image "
|
||||
"(status %04x)\n", drive, status );
|
||||
DBGC ( drive, "INT13 drive %02x could not read El Torito boot "
|
||||
"image (status %04x)\n", drive, status );
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1503,7 +1511,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
* Attempt to boot from an INT 13 drive
|
||||
*
|
||||
* @v drive Drive number
|
||||
* @v filename Filename (or NULL to use default)
|
||||
* @v config Boot configuration parameters
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* This boots from the specified INT 13 drive by loading the Master
|
||||
@ -1513,7 +1521,8 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
|
||||
*
|
||||
* Note that this function can never return success, by definition.
|
||||
*/
|
||||
static int int13_boot ( unsigned int drive, const char *filename __unused ) {
|
||||
static int int13_boot ( unsigned int drive,
|
||||
struct san_boot_config *config __unused ) {
|
||||
struct memory_map memmap;
|
||||
struct segoff address;
|
||||
int rc;
|
||||
@ -1533,8 +1542,8 @@ static int int13_boot ( unsigned int drive, const char *filename __unused ) {
|
||||
/* Jump to boot sector */
|
||||
if ( ( rc = call_bootsector ( address.segment, address.offset,
|
||||
drive ) ) != 0 ) {
|
||||
DBG ( "INT13 drive %02x boot returned: %s\n",
|
||||
drive, strerror ( rc ) );
|
||||
DBGC ( drive, "INT13 drive %02x boot returned: %s\n",
|
||||
drive, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -165,24 +165,27 @@ static void pcicloud_init ( void ) {
|
||||
static struct pci_api *apis[] = {
|
||||
&ecam_api, &pcibios_api, &pcidirect_api
|
||||
};
|
||||
struct pci_range range;
|
||||
struct pci_device pci;
|
||||
uint32_t busdevfn;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Select first API that successfully discovers an address range */
|
||||
/* Select first API that successfully discovers a PCI device */
|
||||
for ( i = 0 ; i < ( sizeof ( apis ) / sizeof ( apis[0] ) ) ; i++ ) {
|
||||
pcicloud = apis[i];
|
||||
pcicloud_discover ( 0, &range );
|
||||
if ( range.count != 0 ) {
|
||||
DBGC ( pcicloud, "PCICLOUD selected %s API\n",
|
||||
pcicloud->name );
|
||||
break;
|
||||
busdevfn = 0;
|
||||
if ( ( rc = pci_find_next ( &pci, &busdevfn ) ) == 0 ) {
|
||||
DBGC ( pcicloud, "PCICLOUD selected %s API (found "
|
||||
PCI_FMT ")\n", pcicloud->name,
|
||||
PCI_ARGS ( &pci ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* The PCI direct API can never fail discovery since the range
|
||||
* is hardcoded.
|
||||
*/
|
||||
assert ( range.count != 0 );
|
||||
/* Fall back to using final attempted API if no devices found */
|
||||
pcicloud = apis[ i - 1 ];
|
||||
DBGC ( pcicloud, "PCICLOUD selected %s API (nothing detected)\n",
|
||||
pcicloud->name );
|
||||
}
|
||||
|
||||
/** Cloud VM PCI configuration space access initialisation function */
|
||||
|
||||
@ -375,9 +375,10 @@ int pxe_start_nbp ( void ) {
|
||||
* Notify BIOS of existence of network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v priv Private data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int pxe_notify ( struct net_device *netdev ) {
|
||||
static int pxe_notify ( struct net_device *netdev, void *priv __unused ) {
|
||||
|
||||
/* Do nothing if we already have a network device */
|
||||
if ( pxe_netdev )
|
||||
|
||||
@ -26,6 +26,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
|
||||
|
||||
#include "librm.h"
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
|
||||
.code32
|
||||
|
||||
@ -207,65 +207,35 @@ struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
* Create per-netdevice GuestInfo settings
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v priv Private data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int guestinfo_net_probe ( struct net_device *netdev ) {
|
||||
struct settings *settings;
|
||||
static int guestinfo_net_probe ( struct net_device *netdev, void *priv ) {
|
||||
struct settings *settings = priv;
|
||||
int rc;
|
||||
|
||||
/* Do nothing unless we have a GuestInfo channel available */
|
||||
if ( guestinfo_channel < 0 )
|
||||
return 0;
|
||||
|
||||
/* Allocate and initialise settings block */
|
||||
settings = zalloc ( sizeof ( *settings ) );
|
||||
if ( ! settings ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
settings_init ( settings, &guestinfo_settings_operations, NULL, NULL );
|
||||
|
||||
/* Register settings */
|
||||
/* Initialise and register settings */
|
||||
settings_init ( settings, &guestinfo_settings_operations,
|
||||
&netdev->refcnt, NULL );
|
||||
if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
|
||||
"vmware" ) ) != 0 ) {
|
||||
DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
|
||||
settings, netdev->name, strerror ( rc ) );
|
||||
goto err_register;
|
||||
return rc;
|
||||
}
|
||||
DBGC ( settings, "GuestInfo %p registered for %s\n",
|
||||
settings, netdev->name );
|
||||
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
free ( settings );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove per-netdevice GuestInfo settings
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void guestinfo_net_remove ( struct net_device *netdev ) {
|
||||
struct settings *parent = netdev_settings ( netdev );
|
||||
struct settings *settings;
|
||||
|
||||
list_for_each_entry ( settings, &parent->children, siblings ) {
|
||||
if ( settings->op == &guestinfo_settings_operations ) {
|
||||
DBGC ( settings, "GuestInfo %p unregistered for %s\n",
|
||||
settings, netdev->name );
|
||||
unregister_settings ( settings );
|
||||
free ( settings );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** GuestInfo per-netdevice driver */
|
||||
struct net_driver guestinfo_net_driver __net_driver = {
|
||||
.name = "GuestInfo",
|
||||
.priv_len = sizeof ( struct settings ),
|
||||
.probe = guestinfo_net_probe,
|
||||
.remove = guestinfo_net_remove,
|
||||
};
|
||||
|
||||
@ -5,10 +5,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define STACK_SEG 0x0200
|
||||
#define STACK_SIZE 0x2000
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
|
||||
/*
|
||||
* Find active partition
|
||||
|
||||
@ -24,11 +24,11 @@ FILE_LICENCE ( GPL2_ONLY )
|
||||
|
||||
.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.org 0
|
||||
.arch i386
|
||||
.text
|
||||
.section ".prefix", "ax", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.globl _dsk_start
|
||||
_dsk_start:
|
||||
|
||||
|
||||
@ -36,10 +36,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define PSP_CMDLINE_LEN 0x80
|
||||
#define PSP_CMDLINE_START 0x81
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
.section ".prefix", "awx", @progbits
|
||||
|
||||
signature:
|
||||
|
||||
@ -2,10 +2,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
.org 0
|
||||
.globl _hd_start
|
||||
_hd_start:
|
||||
|
||||
@ -26,6 +26,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/* Image compression enabled */
|
||||
|
||||
@ -4,9 +4,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#define BZI_LOAD_HIGH_ADDR 0x100000
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.globl _lkrn_start
|
||||
_lkrn_start:
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
.org 0
|
||||
|
||||
.globl mbr
|
||||
|
||||
@ -41,9 +41,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define _pcirom_start _mrom_start
|
||||
#include "pciromprefix.S"
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/* Obtain access to payload by exposing the expansion ROM BAR at the
|
||||
* address currently used by a suitably large memory BAR on the same
|
||||
|
||||
@ -2,9 +2,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
.org 0
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.org 0
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
.section ".prefix", "ax", @progbits
|
||||
.code16
|
||||
_prefix:
|
||||
|
||||
.section ".text16", "ax", @progbits
|
||||
|
||||
@ -11,10 +11,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#define PXE_HACK_EB54 0x0001
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
|
||||
#include <librm.h>
|
||||
#include <undi.h>
|
||||
|
||||
@ -8,10 +8,10 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define BUSTYPE "PCIR"
|
||||
#endif
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
|
||||
@ -2,7 +2,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include <librm.h>
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "ax", @progbits
|
||||
|
||||
@ -43,7 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code32
|
||||
.arch i486
|
||||
.section ".prefix.lib", "ax", @progbits
|
||||
|
||||
|
||||
@ -2,10 +2,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include <config/console.h>
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
.org 0
|
||||
|
||||
#include "mbr.S"
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@ -31,10 +31,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
/* Breakpoint for when debugging under bochs */
|
||||
#define BOCHSBP xchgw %bx, %bx
|
||||
|
||||
.text
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".text16", "awx", @progbits
|
||||
.code16
|
||||
|
||||
/****************************************************************************
|
||||
* init_libkir (real-mode or 16:xx protected-mode far call)
|
||||
|
||||
@ -83,6 +83,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define if64 if 0
|
||||
#endif
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
|
||||
/****************************************************************************
|
||||
* Global descriptor table
|
||||
*
|
||||
@ -1630,3 +1632,70 @@ init_pages:
|
||||
|
||||
/* Return */
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* sipi (real-mode jump)
|
||||
*
|
||||
* Handle Startup IPI
|
||||
*
|
||||
* This code must be copied to a page-aligned boundary in base memory.
|
||||
* It will be entered with %cs:0000 pointing to the start of the code.
|
||||
* The stack pointer is undefined and so no stack space can be used.
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16.sipi", "ax", @progbits
|
||||
.code16
|
||||
.globl sipi
|
||||
sipi:
|
||||
/* Retrieve rm_ds from copy */
|
||||
movw %cs:( sipi_ds - sipi ), %ax
|
||||
movw %ax, %ds
|
||||
|
||||
/* Load GDT and switch to protected mode */
|
||||
data32 lgdt gdtr
|
||||
movl %cr0, %eax
|
||||
orb $CR0_PE, %al
|
||||
movl %eax, %cr0
|
||||
data32 ljmp $VIRTUAL_CS, $VIRTUAL(1f)
|
||||
|
||||
/* Copy of rm_ds required to access GDT */
|
||||
.globl sipi_ds
|
||||
sipi_ds:
|
||||
.word 0
|
||||
|
||||
/* Length of real-mode SIPI handler to be copied */
|
||||
.globl sipi_len
|
||||
.equ sipi_len, . - sipi
|
||||
|
||||
.section ".text.sipi", "ax", @progbits
|
||||
.code32
|
||||
1: /* Set up protected-mode segment registers (with no stack) */
|
||||
movw $VIRTUAL_DS, %ax
|
||||
movw %ax, %ds
|
||||
movw %ax, %ss
|
||||
movw $PHYSICAL_DS, %ax
|
||||
movw %ax, %es
|
||||
movw %ax, %fs
|
||||
movw %ax, %gs
|
||||
|
||||
/* Load register state and clear stack pointer */
|
||||
movl $VIRTUAL(sipi_regs), %esp
|
||||
popal
|
||||
|
||||
/* Switch to flat physical addressing */
|
||||
movw $PHYSICAL_DS, %sp
|
||||
movw %sp, %ds
|
||||
movw %sp, %ss
|
||||
|
||||
/* Clear stack pointer */
|
||||
xorl %esp, %esp
|
||||
|
||||
/* Jump to protected-mode SIPI handler */
|
||||
ljmp %cs:*VIRTUAL(sipi_handler)
|
||||
|
||||
/* Protected-mode SIPI handler vector */
|
||||
.section ".data.sipi_handler", "aw", @progbits
|
||||
.globl sipi_handler
|
||||
sipi_handler:
|
||||
.long 0, PHYSICAL_CS
|
||||
|
||||
@ -45,6 +45,9 @@ struct idtr64 idtr64 = {
|
||||
.limit = ( sizeof ( idt64 ) - 1 ),
|
||||
};
|
||||
|
||||
/** Startup IPI register state */
|
||||
struct i386_regs sipi_regs;
|
||||
|
||||
/** Length of stack dump */
|
||||
#define STACK_DUMP_LEN 128
|
||||
|
||||
@ -402,6 +405,29 @@ __asmcall void check_fxsr ( struct i386_all_regs *regs ) {
|
||||
( ( regs->flags & CF ) ? " not" : "" ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up startup IPI handler
|
||||
*
|
||||
* @v vector Startup IPI vector
|
||||
* @v handler Protected-mode startup IPI handler physical address
|
||||
* @v regs Initial register state
|
||||
*/
|
||||
void setup_sipi ( unsigned int vector, uint32_t handler,
|
||||
struct i386_regs *regs ) {
|
||||
|
||||
/* Record protected-mode handler */
|
||||
sipi_handler = handler;
|
||||
|
||||
/* Update copy of rm_ds */
|
||||
sipi_ds = rm_ds;
|
||||
|
||||
/* Save register state */
|
||||
memcpy ( &sipi_regs, regs, sizeof ( sipi_regs ) );
|
||||
|
||||
/* Copy real-mode handler */
|
||||
copy_to_real ( ( vector << 8 ), 0, sipi, ( ( size_t ) sipi_len ) );
|
||||
}
|
||||
|
||||
PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
|
||||
PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
|
||||
PROVIDE_UACCESS_INLINE ( librm, virt_to_user );
|
||||
|
||||
@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define SIGFPE 8
|
||||
#define SIGSTKFLT 16
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.section ".text.gdbmach_interrupt", "ax", @progbits
|
||||
.code64
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code64
|
||||
|
||||
|
||||
1
src/bin/.gitignore
vendored
1
src/bin/.gitignore
vendored
@ -1 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
|
||||
@ -188,6 +188,9 @@ REQUIRE_OBJECT ( zlib );
|
||||
#ifdef IMAGE_GZIP
|
||||
REQUIRE_OBJECT ( gzip );
|
||||
#endif
|
||||
#ifdef IMAGE_UCODE
|
||||
REQUIRE_OBJECT ( ucode );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in all requested commands
|
||||
@ -290,6 +293,9 @@ REQUIRE_OBJECT ( cert_cmd );
|
||||
#ifdef IMAGE_MEM_CMD
|
||||
REQUIRE_OBJECT ( image_mem_cmd );
|
||||
#endif
|
||||
#ifdef SHIM_CMD
|
||||
REQUIRE_OBJECT ( shim_cmd );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in miscellaneous objects
|
||||
@ -352,6 +358,9 @@ REQUIRE_OBJECT ( vram_settings );
|
||||
#ifdef ACPI_SETTINGS
|
||||
REQUIRE_OBJECT ( acpi_settings );
|
||||
#endif
|
||||
#ifdef EFI_SETTINGS
|
||||
REQUIRE_OBJECT ( efi_settings );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in selected keyboard map
|
||||
|
||||
@ -83,6 +83,11 @@ REQUIRE_OBJECT ( oid_sha512_224 );
|
||||
REQUIRE_OBJECT ( oid_sha512_256 );
|
||||
#endif
|
||||
|
||||
/* X25519 */
|
||||
#if defined ( CRYPTO_CURVE_X25519 )
|
||||
REQUIRE_OBJECT ( oid_x25519 );
|
||||
#endif
|
||||
|
||||
/* RSA and MD5 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_DIGEST_MD5 )
|
||||
REQUIRE_OBJECT ( rsa_md5 );
|
||||
@ -114,25 +119,79 @@ REQUIRE_OBJECT ( rsa_sha512 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-CBC, and SHA-1 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA1 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 )
|
||||
REQUIRE_OBJECT ( rsa_aes_cbc_sha1 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-CBC, and SHA-256 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_CBC ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA256 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( rsa_aes_cbc_sha256 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-GCM, and SHA-256 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA256 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( rsa_aes_gcm_sha256 );
|
||||
#endif
|
||||
|
||||
/* RSA, AES-GCM, and SHA-384 */
|
||||
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \
|
||||
defined ( CRYPTO_DIGEST_SHA384 )
|
||||
#if defined ( CRYPTO_EXCHANGE_PUBKEY ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( rsa_aes_gcm_sha384 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-CBC, and SHA-1 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_cbc_sha1 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-CBC, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_cbc_sha256 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-GCM, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha256 );
|
||||
#endif
|
||||
|
||||
/* DHE, RSA, AES-GCM, and SHA-384 */
|
||||
#if defined ( CRYPTO_EXCHANGE_DHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( dhe_rsa_aes_gcm_sha384 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-CBC, and SHA-1 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA1 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha1 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-CBC, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha256 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-CBC, and SHA-384 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_CBC ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_cbc_sha384 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-GCM, and SHA-256 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA256 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_gcm_sha256 );
|
||||
#endif
|
||||
|
||||
/* ECDHE, RSA, AES-GCM, and SHA-384 */
|
||||
#if defined ( CRYPTO_EXCHANGE_ECDHE ) && defined ( CRYPTO_PUBKEY_RSA ) && \
|
||||
defined ( CRYPTO_CIPHER_AES_GCM ) && defined ( CRYPTO_DIGEST_SHA384 )
|
||||
REQUIRE_OBJECT ( ecdhe_rsa_aes_gcm_sha384 );
|
||||
#endif
|
||||
|
||||
42
src/config/config_eap.c
Normal file
42
src/config/config_eap.c
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <config/general.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* EAP configuration options
|
||||
*
|
||||
*/
|
||||
|
||||
PROVIDE_REQUIRING_SYMBOL();
|
||||
|
||||
/*
|
||||
* Drag in EAP authentication methods
|
||||
*/
|
||||
#ifdef EAP_METHOD_MD5
|
||||
REQUIRE_OBJECT ( eap_md5 );
|
||||
#endif
|
||||
#ifdef EAP_METHOD_MSCHAPV2
|
||||
REQUIRE_OBJECT ( eap_mschapv2 );
|
||||
#endif
|
||||
@ -12,6 +12,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** Minimum TLS version */
|
||||
#define TLS_VERSION_MIN TLS_VERSION_TLS_1_1
|
||||
|
||||
/** Public-key exchange algorithm */
|
||||
#define CRYPTO_EXCHANGE_PUBKEY
|
||||
|
||||
/** DHE key exchange algorithm */
|
||||
#define CRYPTO_EXCHANGE_DHE
|
||||
|
||||
/** ECDHE key exchange algorithm */
|
||||
#define CRYPTO_EXCHANGE_ECDHE
|
||||
|
||||
/** RSA public-key algorithm */
|
||||
#define CRYPTO_PUBKEY_RSA
|
||||
|
||||
@ -48,6 +57,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** SHA-512/256 digest algorithm */
|
||||
//#define CRYPTO_DIGEST_SHA512_256
|
||||
|
||||
/** X25519 elliptic curve */
|
||||
#define CRYPTO_CURVE_X25519
|
||||
|
||||
/** Margin of error (in seconds) allowed in signed timestamps
|
||||
*
|
||||
* We default to allowing a reasonable margin of error: 12 hours to
|
||||
|
||||
@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define REBOOT_EFI
|
||||
#define ACPI_EFI
|
||||
#define FDT_EFI
|
||||
#define MPAPI_EFI
|
||||
|
||||
#define NET_PROTO_IPV6 /* IPv6 protocol */
|
||||
#define NET_PROTO_LLDP /* Link Layer Discovery protocol */
|
||||
@ -48,6 +49,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#define REBOOT_CMD /* Reboot command */
|
||||
|
||||
#define EFI_SETTINGS /* EFI variable settings */
|
||||
|
||||
#if defined ( __i386__ ) || defined ( __x86_64__ )
|
||||
#define IOAPI_X86
|
||||
#define NAP_EFIX86
|
||||
@ -65,4 +68,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define IMAGE_GZIP /* GZIP image support */
|
||||
#endif
|
||||
|
||||
#if defined ( __loongarch__ )
|
||||
#define IOAPI_LOONG64
|
||||
#define NAP_EFILOONG64
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_DEFAULTS_EFI_H */
|
||||
|
||||
@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#define PCIAPI_LINUX
|
||||
#define DMAAPI_FLAT
|
||||
#define ACPI_LINUX
|
||||
#define MPAPI_NULL
|
||||
|
||||
#define DRIVERS_LINUX
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define TIME_RTC
|
||||
#define REBOOT_PCBIOS
|
||||
#define ACPI_RSDP
|
||||
#define MPAPI_PCBIOS
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define IOMAP_PAGES
|
||||
|
||||
@ -91,6 +91,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define CRYPTO_80211_WPA /* WPA Personal, authenticating with passphrase */
|
||||
#define CRYPTO_80211_WPA2 /* Add support for stronger WPA cryptography */
|
||||
|
||||
/*
|
||||
* 802.1x EAP authentication methods
|
||||
*
|
||||
*/
|
||||
#define EAP_METHOD_MD5 /* MD5-Challenge port authentication */
|
||||
//#define EAP_METHOD_MSCHAPV2 /* MS-CHAPv2 port authentication */
|
||||
|
||||
/*
|
||||
* Name resolution modules
|
||||
*
|
||||
@ -120,6 +127,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define IMAGE_PEM /* PEM image support */
|
||||
//#define IMAGE_ZLIB /* ZLIB image support */
|
||||
//#define IMAGE_GZIP /* GZIP image support */
|
||||
//#define IMAGE_UCODE /* Microcode update image support */
|
||||
|
||||
/*
|
||||
* Command-line commands to include
|
||||
@ -160,6 +168,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
//#define CERT_CMD /* Certificate management commands */
|
||||
//#define IMAGE_MEM_CMD /* Read memory command */
|
||||
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
|
||||
#define SHIM_CMD /* EFI shim command (or dummy command) */
|
||||
|
||||
/*
|
||||
* ROM-specific options
|
||||
|
||||
1
src/config/local/.gitignore
vendored
1
src/config/local/.gitignore
vendored
@ -1 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <config/defaults.h>
|
||||
|
||||
#define PCI_SETTINGS /* PCI device settings */
|
||||
//#define CPUID_SETTINGS /* CPUID settings */
|
||||
//#define MEMMAP_SETTINGS /* Memory map settings */
|
||||
|
||||
@ -78,12 +78,23 @@ int hex_decode ( char separator, const char *encoded, void *data, size_t len ) {
|
||||
unsigned int count = 0;
|
||||
unsigned int sixteens;
|
||||
unsigned int units;
|
||||
int optional;
|
||||
|
||||
/* Strip out optionality flag from separator character */
|
||||
optional = ( separator & HEX_DECODE_OPTIONAL );
|
||||
separator &= ~HEX_DECODE_OPTIONAL;
|
||||
|
||||
/* Decode string */
|
||||
while ( *encoded ) {
|
||||
|
||||
/* Check separator, if applicable */
|
||||
if ( count && separator && ( ( *(encoded++) != separator ) ) )
|
||||
return -EINVAL;
|
||||
if ( count && separator ) {
|
||||
if ( *encoded == separator ) {
|
||||
encoded++;
|
||||
} else if ( ! optional ) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract digits. Note that either digit may be NUL,
|
||||
* which would be interpreted as an invalid value by
|
||||
|
||||
@ -46,11 +46,20 @@ struct cached_dhcp_packet {
|
||||
struct dhcp_packet *dhcppkt;
|
||||
/** VLAN tag (if applicable) */
|
||||
unsigned int vlan;
|
||||
/** Flags */
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/** Cached DHCP packet should be retained */
|
||||
#define CACHEDHCP_RETAIN 0x0001
|
||||
|
||||
/** Cached DHCP packet has been used */
|
||||
#define CACHEDHCP_USED 0x0002
|
||||
|
||||
/** Cached DHCPACK */
|
||||
struct cached_dhcp_packet cached_dhcpack = {
|
||||
.name = DHCP_SETTINGS_NAME,
|
||||
.flags = CACHEDHCP_RETAIN,
|
||||
};
|
||||
|
||||
/** Cached ProxyDHCPOFFER */
|
||||
@ -101,8 +110,8 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
|
||||
size_t ll_addr_len;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if cache is empty */
|
||||
if ( ! cache->dhcppkt )
|
||||
/* Do nothing if cache is empty or already in use */
|
||||
if ( ( ! cache->dhcppkt ) || ( cache->flags & CACHEDHCP_USED ) )
|
||||
return 0;
|
||||
chaddr = cache->dhcppkt->dhcphdr->chaddr;
|
||||
|
||||
@ -169,8 +178,12 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Free cached DHCP packet */
|
||||
cachedhcp_free ( cache );
|
||||
/* Mark as used */
|
||||
cache->flags |= CACHEDHCP_USED;
|
||||
|
||||
/* Free cached DHCP packet, if applicable */
|
||||
if ( ! ( cache->flags & CACHEDHCP_RETAIN ) )
|
||||
cachedhcp_free ( cache );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -246,10 +259,10 @@ int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan,
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached DHCP packet startup function
|
||||
* Cached DHCP packet early startup function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_startup ( void ) {
|
||||
static void cachedhcp_startup_early ( void ) {
|
||||
|
||||
/* Apply cached ProxyDHCPOFFER, if any */
|
||||
cachedhcp_apply ( &cached_proxydhcp, NULL );
|
||||
@ -258,6 +271,20 @@ static void cachedhcp_startup ( void ) {
|
||||
/* Apply cached PXEBSACK, if any */
|
||||
cachedhcp_apply ( &cached_pxebs, NULL );
|
||||
cachedhcp_free ( &cached_pxebs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache DHCP packet late startup function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_startup_late ( void ) {
|
||||
|
||||
/* Clear retention flag */
|
||||
cached_dhcpack.flags &= ~CACHEDHCP_RETAIN;
|
||||
|
||||
/* Free cached DHCPACK, if used by a network device */
|
||||
if ( cached_dhcpack.flags & CACHEDHCP_USED )
|
||||
cachedhcp_free ( &cached_dhcpack );
|
||||
|
||||
/* Report unclaimed DHCPACK, if any. Do not free yet, since
|
||||
* it may still be claimed by a dynamically created device
|
||||
@ -284,10 +311,16 @@ static void cachedhcp_shutdown ( int booting __unused ) {
|
||||
cachedhcp_free ( &cached_dhcpack );
|
||||
}
|
||||
|
||||
/** Cached DHCPACK startup function */
|
||||
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
.name = "cachedhcp",
|
||||
.startup = cachedhcp_startup,
|
||||
/** Cached DHCP packet early startup function */
|
||||
struct startup_fn cachedhcp_early_fn __startup_fn ( STARTUP_EARLY ) = {
|
||||
.name = "cachedhcp1",
|
||||
.startup = cachedhcp_startup_early,
|
||||
};
|
||||
|
||||
/** Cached DHCP packet late startup function */
|
||||
struct startup_fn cachedhcp_late_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
.name = "cachedhcp2",
|
||||
.startup = cachedhcp_startup_late,
|
||||
.shutdown = cachedhcp_shutdown,
|
||||
};
|
||||
|
||||
@ -295,9 +328,10 @@ struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
* Apply cached DHCPACK to network device, if applicable
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v priv Private data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cachedhcp_probe ( struct net_device *netdev ) {
|
||||
static int cachedhcp_probe ( struct net_device *netdev, void *priv __unused ) {
|
||||
|
||||
/* Apply cached DHCPACK to network device, if applicable */
|
||||
return cachedhcp_apply ( &cached_dhcpack, netdev );
|
||||
@ -308,3 +342,25 @@ struct net_driver cachedhcp_driver __net_driver = {
|
||||
.name = "cachedhcp",
|
||||
.probe = cachedhcp_probe,
|
||||
};
|
||||
|
||||
/**
|
||||
* Recycle cached DHCPACK
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v priv Private data
|
||||
*/
|
||||
void cachedhcp_recycle ( struct net_device *netdev ) {
|
||||
struct cached_dhcp_packet *cache = &cached_dhcpack;
|
||||
struct settings *settings;
|
||||
|
||||
/* Return DHCPACK to cache, if applicable */
|
||||
settings = find_child_settings ( netdev_settings ( netdev ),
|
||||
cache->name );
|
||||
if ( cache->dhcppkt && ( settings == &cache->dhcppkt->settings ) ) {
|
||||
DBGC ( colour, "CACHEDHCP %s recycled from %s\n",
|
||||
cache->name, netdev->name );
|
||||
assert ( cache->flags & CACHEDHCP_USED );
|
||||
unregister_settings ( settings );
|
||||
cache->flags &= ~CACHEDHCP_USED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ static int dummy_san_hook ( unsigned int drive, struct uri **uris,
|
||||
|
||||
/* Register SAN device */
|
||||
if ( ( rc = register_sandev ( sandev, drive, flags ) ) != 0 ) {
|
||||
DBGC ( sandev, "SAN %#02x could not register: %s\n",
|
||||
DBGC ( sandev->drive, "SAN %#02x could not register: %s\n",
|
||||
sandev->drive, strerror ( rc ) );
|
||||
goto err_register;
|
||||
}
|
||||
@ -80,7 +80,7 @@ static void dummy_san_unhook ( unsigned int drive ) {
|
||||
/* Find drive */
|
||||
sandev = sandev_find ( drive );
|
||||
if ( ! sandev ) {
|
||||
DBG ( "SAN %#02x does not exist\n", drive );
|
||||
DBGC ( drive, "SAN %#02x does not exist\n", drive );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -95,11 +95,11 @@ static void dummy_san_unhook ( unsigned int drive ) {
|
||||
* Boot from dummy SAN device
|
||||
*
|
||||
* @v drive Drive number
|
||||
* @v filename Filename (or NULL to use default)
|
||||
* @v config Boot configuration parameters
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int dummy_san_boot ( unsigned int drive __unused,
|
||||
const char *filename __unused ) {
|
||||
struct san_boot_config *config __unused ) {
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@ -56,8 +56,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** List of registered images */
|
||||
struct list_head images = LIST_HEAD_INIT ( images );
|
||||
|
||||
/** Image selected for execution */
|
||||
struct image_tag selected_image __image_tag = {
|
||||
.name = "SELECTED",
|
||||
};
|
||||
|
||||
/** Currently-executing image */
|
||||
struct image *current_image;
|
||||
struct image_tag current_image __image_tag = {
|
||||
.name = "CURRENT",
|
||||
};
|
||||
|
||||
/** Current image trust requirement */
|
||||
static int require_trusted_images = 0;
|
||||
@ -72,8 +79,13 @@ static int require_trusted_images_permanent = 0;
|
||||
*/
|
||||
static void free_image ( struct refcnt *refcnt ) {
|
||||
struct image *image = container_of ( refcnt, struct image, refcnt );
|
||||
struct image_tag *tag;
|
||||
|
||||
DBGC ( image, "IMAGE %s freed\n", image->name );
|
||||
for_each_table_entry ( tag, IMAGE_TAGS ) {
|
||||
if ( tag->image == image )
|
||||
tag->image = NULL;
|
||||
}
|
||||
free ( image->name );
|
||||
free ( image->cmdline );
|
||||
uri_put ( image->uri );
|
||||
@ -122,10 +134,13 @@ int image_set_uri ( struct image *image, struct uri *uri ) {
|
||||
int rc;
|
||||
|
||||
/* Set name, if image does not already have one */
|
||||
if ( uri->path && ( ! ( image->name && image->name[0] ) ) ) {
|
||||
name = basename ( ( char * ) uri->path );
|
||||
if ( ( rc = image_set_name ( image, name ) ) != 0 )
|
||||
return rc;
|
||||
if ( ! ( image->name && image->name[0] ) ) {
|
||||
name = ( uri->path ? uri->path : uri->opaque );
|
||||
if ( name ) {
|
||||
name = basename ( ( char * ) name );
|
||||
if ( ( rc = image_set_name ( image, name ) ) != 0 )
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update image URI */
|
||||
@ -261,12 +276,6 @@ int register_image ( struct image *image ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Avoid ending up with multiple "selected" images on
|
||||
* re-registration
|
||||
*/
|
||||
if ( image_find_selected() )
|
||||
image->flags &= ~IMAGE_SELECTED;
|
||||
|
||||
/* Add to image list */
|
||||
image_get ( image );
|
||||
image->flags |= IMAGE_REGISTERED;
|
||||
@ -320,6 +329,23 @@ struct image * find_image ( const char *name ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find image by tag
|
||||
*
|
||||
* @v tag Image tag
|
||||
* @ret image Executable image, or NULL
|
||||
*/
|
||||
struct image * find_image_tag ( struct image_tag *tag ) {
|
||||
struct image *image;
|
||||
|
||||
for_each_image ( image ) {
|
||||
if ( tag->image == image )
|
||||
return image;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute image
|
||||
*
|
||||
@ -346,13 +372,13 @@ int image_exec ( struct image *image ) {
|
||||
if ( image->uri )
|
||||
churi ( image->uri );
|
||||
|
||||
/* Preserve record of any currently-running image */
|
||||
saved_current_image = current_image;
|
||||
/* Set as currently running image */
|
||||
saved_current_image = image_tag ( image, ¤t_image );
|
||||
|
||||
/* Take out a temporary reference to the image, so that it
|
||||
* does not get freed when temporarily unregistered.
|
||||
*/
|
||||
current_image = image_get ( image );
|
||||
image_get ( image );
|
||||
|
||||
/* Check that this image can be executed */
|
||||
if ( ! ( image->type && image->type->exec ) ) {
|
||||
@ -419,7 +445,7 @@ int image_exec ( struct image *image ) {
|
||||
image_put ( image );
|
||||
|
||||
/* Restore previous currently-running image */
|
||||
current_image = saved_current_image;
|
||||
image_tag ( saved_current_image, ¤t_image );
|
||||
|
||||
/* Reset current working directory */
|
||||
churi ( old_cwuri );
|
||||
@ -442,7 +468,7 @@ int image_exec ( struct image *image ) {
|
||||
* registered until the currently-executing image returns.
|
||||
*/
|
||||
int image_replace ( struct image *replacement ) {
|
||||
struct image *image = current_image;
|
||||
struct image *image = current_image.image;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
@ -478,37 +504,17 @@ int image_replace ( struct image *replacement ) {
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int image_select ( struct image *image ) {
|
||||
struct image *tmp;
|
||||
|
||||
/* Unselect all other images */
|
||||
for_each_image ( tmp )
|
||||
tmp->flags &= ~IMAGE_SELECTED;
|
||||
|
||||
/* Check that this image can be executed */
|
||||
if ( ! ( image->type && image->type->exec ) )
|
||||
return -ENOEXEC;
|
||||
|
||||
/* Mark image as selected */
|
||||
image->flags |= IMAGE_SELECTED;
|
||||
image_tag ( image, &selected_image );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find selected image
|
||||
*
|
||||
* @ret image Executable image, or NULL
|
||||
*/
|
||||
struct image * image_find_selected ( void ) {
|
||||
struct image *image;
|
||||
|
||||
for_each_image ( image ) {
|
||||
if ( image->flags & IMAGE_SELECTED )
|
||||
return image;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change image trust requirement
|
||||
*
|
||||
|
||||
@ -285,6 +285,7 @@ void intf_shutdown ( struct interface *intf, int rc ) {
|
||||
intf_nullify ( intf );
|
||||
|
||||
/* Transfer destination to temporary interface */
|
||||
intf_temp_init ( &tmp, intf );
|
||||
tmp.dest = intf->dest;
|
||||
intf->dest = &null_intf;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user