mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-10-30 07:56:50 +08:00
Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7f2e75519 | |||
| 7f75d320f6 | |||
| 301644ab48 | |||
| 5e69cf08d7 | |||
| 72316b820d | |||
| 486b15b3c1 | |||
| 49404bfea9 | |||
| 748cab7745 | |||
| b053ba1988 | |||
| 4b4a362f07 | |||
| bdb5b4aef4 | |||
| 46937a9df6 | |||
| acbabdb335 | |||
| c9cac76a5c | |||
| be2784649d | |||
| ab5743efc5 | |||
| 633f4f362d | |||
| 53f089b723 | |||
| 950f6b5861 | |||
| 7c82ff0b6b | |||
| 9d9465b140 | |||
| 97635eb71b | |||
| 998edc6ec5 | |||
| 3b4d0cb555 | |||
| 96fb7a0a93 | |||
| d85590b658 | |||
| 59e2b03e6a | |||
| 0e73b48f77 | |||
| 309ac8fd21 | |||
| a064d39768 | |||
| 121d96b903 | |||
| c117e6a481 | |||
| 60d682409e | |||
| 0dc8933f67 | |||
| d2d194bc60 | |||
| c7b76e3adc | |||
| 5a9f476d4f | |||
| b66e27d9b2 | |||
| 77acf6b41f | |||
| 821bb326f8 | |||
| 162cc51b6d | |||
| f417f0b6a5 | |||
| 1c3c5e2b22 | |||
| 039019039e | |||
| c8e50bb0fd | |||
| 5719cde838 | |||
| 122777f789 | |||
| 76e0933d78 | |||
| bf98eae5da | |||
| bb4a10696f | |||
| e965f179e1 | |||
| dc118c5369 | |||
| d7e58c5a81 | |||
| b01781a2b8 | |||
| 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 |
14
.github/workflows/build.yml
vendored
14
.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 }}
|
||||
@ -68,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 }}
|
||||
@ -97,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)
|
||||
167
contrib/cloud/gce-import
Executable file
167
contrib/cloud/gce-import
Executable file
@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from datetime import date
|
||||
import io
|
||||
import subprocess
|
||||
import tarfile
|
||||
from uuid import uuid4
|
||||
|
||||
from google.cloud import compute
|
||||
from google.cloud import exceptions
|
||||
from google.cloud import storage
|
||||
|
||||
IPXE_STORAGE_PREFIX = 'ipxe-upload-temp-'
|
||||
|
||||
FEATURE_GVNIC = compute.GuestOsFeature(type_="GVNIC")
|
||||
FEATURE_IDPF = compute.GuestOsFeature(type_="IDPF")
|
||||
FEATURE_UEFI = compute.GuestOsFeature(type_="UEFI_COMPATIBLE")
|
||||
|
||||
POLICY_PUBLIC = compute.Policy(bindings=[{
|
||||
"role": "roles/compute.imageUser",
|
||||
"members": ["allAuthenticatedUsers"],
|
||||
}])
|
||||
|
||||
def delete_temp_bucket(bucket):
|
||||
"""Remove temporary bucket"""
|
||||
assert bucket.name.startswith(IPXE_STORAGE_PREFIX)
|
||||
for blob in bucket.list_blobs(prefix=IPXE_STORAGE_PREFIX):
|
||||
assert blob.name.startswith(IPXE_STORAGE_PREFIX)
|
||||
blob.delete()
|
||||
if not list(bucket.list_blobs()):
|
||||
bucket.delete()
|
||||
|
||||
def create_temp_bucket(location):
|
||||
"""Create temporary bucket (and remove any stale temporary buckets)"""
|
||||
client = storage.Client()
|
||||
for bucket in client.list_buckets(prefix=IPXE_STORAGE_PREFIX):
|
||||
delete_temp_bucket(bucket)
|
||||
name = '%s%s' % (IPXE_STORAGE_PREFIX, uuid4())
|
||||
return client.create_bucket(name, location=location)
|
||||
|
||||
def create_tarball(image):
|
||||
"""Create raw disk image tarball"""
|
||||
tarball = io.BytesIO()
|
||||
with tarfile.open(fileobj=tarball, mode='w:gz',
|
||||
format=tarfile.GNU_FORMAT) as tar:
|
||||
tar.add(image, arcname='disk.raw')
|
||||
tarball.seek(0)
|
||||
return tarball
|
||||
|
||||
def upload_blob(bucket, image):
|
||||
"""Upload raw disk image blob"""
|
||||
blob = bucket.blob('%s%s.tar.gz' % (IPXE_STORAGE_PREFIX, uuid4()))
|
||||
tarball = create_tarball(image)
|
||||
blob.upload_from_file(tarball)
|
||||
return blob
|
||||
|
||||
def detect_uefi(image):
|
||||
"""Identify UEFI CPU architecture(s)"""
|
||||
mdir = subprocess.run(['mdir', '-b', '-i', image, '::/EFI/BOOT'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
check=False)
|
||||
mapping = {
|
||||
b'BOOTX64.EFI': 'x86_64',
|
||||
b'BOOTAA64.EFI': 'arm64',
|
||||
}
|
||||
uefi = [
|
||||
arch
|
||||
for filename, arch in mapping.items()
|
||||
if filename in mdir.stdout
|
||||
]
|
||||
return uefi
|
||||
|
||||
def image_architecture(uefi):
|
||||
"""Get image architecture"""
|
||||
return uefi[0] if len(uefi) == 1 else None if uefi else 'x86_64'
|
||||
|
||||
def image_features(uefi):
|
||||
"""Get image feature list"""
|
||||
features = [FEATURE_GVNIC, FEATURE_IDPF]
|
||||
if uefi:
|
||||
features.append(FEATURE_UEFI)
|
||||
return features
|
||||
|
||||
def image_name(base, uefi):
|
||||
"""Calculate image name or family name"""
|
||||
suffix = ('-uefi-%s' % uefi[0].replace('_', '-') if len(uefi) == 1 else
|
||||
'-uefi-multi' if uefi else '')
|
||||
return '%s%s' % (base, suffix)
|
||||
|
||||
def create_image(project, basename, basefamily, overwrite, public, bucket,
|
||||
image):
|
||||
"""Create image"""
|
||||
client = compute.ImagesClient()
|
||||
uefi = detect_uefi(image)
|
||||
architecture = image_architecture(uefi)
|
||||
features = image_features(uefi)
|
||||
name = image_name(basename, uefi)
|
||||
family = image_name(basefamily, uefi)
|
||||
if overwrite:
|
||||
try:
|
||||
client.delete(project=project, image=name).result()
|
||||
except exceptions.NotFound:
|
||||
pass
|
||||
blob = upload_blob(bucket, image)
|
||||
disk = compute.RawDisk(source=blob.public_url)
|
||||
image = compute.Image(name=name, family=family, architecture=architecture,
|
||||
guest_os_features=features, raw_disk=disk)
|
||||
client.insert(project=project, image_resource=image).result()
|
||||
if public:
|
||||
request = compute.GlobalSetPolicyRequest(policy=POLICY_PUBLIC)
|
||||
client.set_iam_policy(project=project, resource=name,
|
||||
global_set_policy_request_resource=request)
|
||||
image = client.get(project=project, image=name)
|
||||
return image
|
||||
|
||||
# Parse command-line arguments
|
||||
#
|
||||
parser = argparse.ArgumentParser(description="Import Google Cloud image")
|
||||
parser.add_argument('--name', '-n',
|
||||
help="Base image name")
|
||||
parser.add_argument('--family', '-f',
|
||||
help="Base family 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('--project', '-j', default="ipxe-images",
|
||||
help="Google Cloud project")
|
||||
parser.add_argument('--location', '-l',
|
||||
help="Google Cloud Storage initial location")
|
||||
parser.add_argument('image', nargs='+', help="iPXE disk image")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Use default family name if none specified
|
||||
if not args.family:
|
||||
args.family = 'ipxe'
|
||||
|
||||
# Use default name if none specified
|
||||
if not args.name:
|
||||
args.name = '%s-%s' % (args.family, date.today().strftime('%Y%m%d'))
|
||||
|
||||
# Create temporary upload bucket
|
||||
bucket = create_temp_bucket(args.location)
|
||||
|
||||
# Use one thread per image to maximise parallelism
|
||||
with ThreadPoolExecutor(max_workers=len(args.image)) as executor:
|
||||
futures = {executor.submit(create_image,
|
||||
project=args.project,
|
||||
basename=args.name,
|
||||
basefamily=args.family,
|
||||
overwrite=args.overwrite,
|
||||
public=args.public,
|
||||
bucket=bucket,
|
||||
image=image): image
|
||||
for image in args.image}
|
||||
results = {futures[future]: future.result()
|
||||
for future in as_completed(futures)}
|
||||
|
||||
# Delete temporary upload bucket
|
||||
delete_temp_bucket(bucket)
|
||||
|
||||
# Show created images
|
||||
for image in args.image:
|
||||
result = results[image]
|
||||
print("%s (%s) %s" % (result.name, result.family, result.status))
|
||||
146
contrib/cloud/gce-int13con
Executable file
146
contrib/cloud/gce-int13con
Executable file
@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import textwrap
|
||||
import time
|
||||
from uuid import uuid4
|
||||
|
||||
from google.cloud import compute
|
||||
|
||||
IPXE_LOG_PREFIX = 'ipxe-log-temp-'
|
||||
IPXE_LOG_MAGIC = 'iPXE LOG'
|
||||
IPXE_LOG_END = '----- END OF iPXE LOG -----'
|
||||
|
||||
def get_log_disk(instances, project, zone, name):
|
||||
"""Get log disk source URL"""
|
||||
instance = instances.get(project=project, zone=zone, instance=name)
|
||||
disk = next(x for x in instance.disks if x.boot)
|
||||
return disk.source
|
||||
|
||||
def delete_temp_snapshot(snapshots, project, name):
|
||||
"""Delete temporary snapshot"""
|
||||
assert name.startswith(IPXE_LOG_PREFIX)
|
||||
snapshots.delete(project=project, snapshot=name)
|
||||
|
||||
def delete_temp_snapshots(snapshots, project):
|
||||
"""Delete all old temporary snapshots"""
|
||||
filter = "name eq %s.+" % IPXE_LOG_PREFIX
|
||||
request = compute.ListSnapshotsRequest(project=project, filter=filter)
|
||||
for snapshot in snapshots.list(request=request):
|
||||
delete_temp_snapshot(snapshots, project, snapshot.name)
|
||||
|
||||
def create_temp_snapshot(snapshots, project, source):
|
||||
"""Create temporary snapshot"""
|
||||
name = '%s%s' % (IPXE_LOG_PREFIX, uuid4())
|
||||
snapshot = compute.Snapshot(name=name, source_disk=source)
|
||||
snapshots.insert(project=project, snapshot_resource=snapshot).result()
|
||||
return name
|
||||
|
||||
def delete_temp_instance(instances, project, zone, name):
|
||||
"""Delete log dumper temporary instance"""
|
||||
assert name.startswith(IPXE_LOG_PREFIX)
|
||||
instances.delete(project=project, zone=zone, instance=name)
|
||||
|
||||
def delete_temp_instances(instances, project, zone):
|
||||
"""Delete all old log dumper temporary instances"""
|
||||
filter = "name eq %s.+" % IPXE_LOG_PREFIX
|
||||
request = compute.ListInstancesRequest(project=project, zone=zone,
|
||||
filter=filter)
|
||||
for instance in instances.list(request=request):
|
||||
delete_temp_instance(instances, project, zone, instance.name)
|
||||
|
||||
def create_temp_instance(instances, project, zone, family, image, machine,
|
||||
snapshot):
|
||||
"""Create log dumper temporary instance"""
|
||||
image = "projects/%s/global/images/family/%s" % (family, image)
|
||||
machine_type = "zones/%s/machineTypes/%s" % (zone, machine)
|
||||
logsource = "global/snapshots/%s" % snapshot
|
||||
bootparams = compute.AttachedDiskInitializeParams(source_image=image)
|
||||
bootdisk = compute.AttachedDisk(boot=True, auto_delete=True,
|
||||
initialize_params=bootparams)
|
||||
logparams = compute.AttachedDiskInitializeParams(source_snapshot=logsource)
|
||||
logdisk = compute.AttachedDisk(boot=False, auto_delete=True,
|
||||
initialize_params=logparams,
|
||||
device_name="ipxelog")
|
||||
nic = compute.NetworkInterface()
|
||||
name = '%s%s' % (IPXE_LOG_PREFIX, uuid4())
|
||||
script = textwrap.dedent(f"""
|
||||
#!/bin/sh
|
||||
tr -d '\\000' < /dev/disk/by-id/google-ipxelog-part3 > /dev/ttyS3
|
||||
echo "{IPXE_LOG_END}" > /dev/ttyS3
|
||||
""").strip()
|
||||
items = compute.Items(key="startup-script", value=script)
|
||||
metadata = compute.Metadata(items=[items])
|
||||
instance = compute.Instance(name=name, machine_type=machine_type,
|
||||
network_interfaces=[nic], metadata=metadata,
|
||||
disks=[bootdisk, logdisk])
|
||||
instances.insert(project=project, zone=zone,
|
||||
instance_resource=instance).result()
|
||||
return name
|
||||
|
||||
def get_log_output(instances, project, zone, name):
|
||||
"""Get iPXE log output"""
|
||||
request = compute.GetSerialPortOutputInstanceRequest(project=project,
|
||||
zone=zone, port=4,
|
||||
instance=name)
|
||||
while True:
|
||||
log = instances.get_serial_port_output(request=request).contents.strip()
|
||||
if log.endswith(IPXE_LOG_END):
|
||||
if log.startswith(IPXE_LOG_MAGIC):
|
||||
return log[len(IPXE_LOG_MAGIC):-len(IPXE_LOG_END)]
|
||||
else:
|
||||
return log[:-len(IPXE_LOG_END)]
|
||||
time.sleep(1)
|
||||
|
||||
# Parse command-line arguments
|
||||
#
|
||||
parser = argparse.ArgumentParser(description="Import Google Cloud image")
|
||||
parser.add_argument('--project', '-j', default="ipxe-images",
|
||||
help="Google Cloud project")
|
||||
parser.add_argument('--zone', '-z', required=True,
|
||||
help="Google Cloud zone")
|
||||
parser.add_argument('--family', '-f', default="debian-cloud",
|
||||
help="Helper OS image family")
|
||||
parser.add_argument('--image', '-i', default="debian-12",
|
||||
help="Helper OS image")
|
||||
parser.add_argument('--machine', '-m', default="e2-micro",
|
||||
help="Helper machine type")
|
||||
parser.add_argument('instance', help="Instance name")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Construct client objects
|
||||
#
|
||||
instances = compute.InstancesClient()
|
||||
snapshots = compute.SnapshotsClient()
|
||||
|
||||
# Clean up old temporary objects
|
||||
#
|
||||
delete_temp_instances(instances, project=args.project, zone=args.zone)
|
||||
delete_temp_snapshots(snapshots, project=args.project)
|
||||
|
||||
# Create log disk snapshot
|
||||
#
|
||||
logdisk = get_log_disk(instances, project=args.project, zone=args.zone,
|
||||
name=args.instance)
|
||||
logsnap = create_temp_snapshot(snapshots, project=args.project, source=logdisk)
|
||||
|
||||
# Create log dumper instance
|
||||
#
|
||||
dumper = create_temp_instance(instances, project=args.project, zone=args.zone,
|
||||
family=args.family, image=args.image,
|
||||
machine=args.machine, snapshot=logsnap)
|
||||
|
||||
# Wait for log output
|
||||
#
|
||||
output = get_log_output(instances, project=args.project, zone=args.zone,
|
||||
name=dumper)
|
||||
|
||||
# Print log output
|
||||
#
|
||||
print(output)
|
||||
|
||||
# Clean up
|
||||
#
|
||||
delete_temp_instance(instances, project=args.project, zone=args.zone,
|
||||
name=dumper)
|
||||
delete_temp_snapshot(snapshots, project=args.project, name=logsnap)
|
||||
80
contrib/crypto/cmsdetach
Executable file
80
contrib/crypto/cmsdetach
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Detach CMS encrypted data.
|
||||
|
||||
Detach encrypted data from a CMS envelopedData or authEnvelopedData
|
||||
message into a separate file.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
import asn1
|
||||
|
||||
# Parse command-line arguments
|
||||
#
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
parser.add_argument("-d", "--data", metavar="FILE",
|
||||
help="Write detached data (without envelope) to FILE")
|
||||
parser.add_argument("-e", "--envelope", metavar="FILE",
|
||||
help="Write envelope (without data) to FILE")
|
||||
parser.add_argument("-o", "--overwrite", action="store_true",
|
||||
help="Overwrite output files")
|
||||
parser.add_argument("file", help="Input envelope file")
|
||||
args = parser.parse_args()
|
||||
if args.data is None and args.envelope is None:
|
||||
parser.error("at least one of --data and --envelope is required")
|
||||
outmode = "wb" if args.overwrite else "xb"
|
||||
|
||||
# Create decoder
|
||||
#
|
||||
decoder = asn1.Decoder()
|
||||
with open(args.file, mode="rb") as fh:
|
||||
decoder.start(fh.read())
|
||||
|
||||
# Create encoder
|
||||
#
|
||||
encoder = asn1.Encoder()
|
||||
encoder.start()
|
||||
|
||||
# Detach encrypted data
|
||||
#
|
||||
data = None
|
||||
datastack = [
|
||||
asn1.Numbers.Sequence, 0, asn1.Numbers.Sequence, asn1.Numbers.Sequence
|
||||
]
|
||||
stack = []
|
||||
while stack or not decoder.eof():
|
||||
if decoder.eof():
|
||||
encoder.leave()
|
||||
decoder.leave()
|
||||
stack.pop()
|
||||
else:
|
||||
tag = decoder.peek()
|
||||
if tag.typ == asn1.Types.Constructed:
|
||||
encoder.enter(nr=tag.nr, cls=tag.cls)
|
||||
decoder.enter()
|
||||
stack.append(tag.nr)
|
||||
else:
|
||||
(tag, value) = decoder.read()
|
||||
if stack == datastack and tag.nr == 0:
|
||||
data = value
|
||||
else:
|
||||
encoder.write(value, nr=tag.nr, cls=tag.cls)
|
||||
envelope = encoder.output()
|
||||
if data is None:
|
||||
parser.error("Input file does not contain any encrypted data")
|
||||
|
||||
# Write envelope (without data), if applicable
|
||||
#
|
||||
if args.envelope:
|
||||
with open(args.envelope, mode=outmode) as fh:
|
||||
fh.write(envelope)
|
||||
|
||||
# Write data (without envelope), if applicable
|
||||
#
|
||||
if args.data:
|
||||
with open(args.data, mode=outmode) as fh:
|
||||
fh.write(data)
|
||||
@ -1,62 +0,0 @@
|
||||
ROM-o-matic web interface for building iPXE ROMs
|
||||
------------------------------------------------
|
||||
|
||||
This web application generates iPXE images and sends them to a web
|
||||
browser.
|
||||
|
||||
Available as part of the iPXE source code distribution, which can be
|
||||
downlaoded from http://etherboot.org/
|
||||
|
||||
Author: Marty Connor <mdc@etherboot.org>
|
||||
License: GPLv2
|
||||
Support: http://etherboot.org/mailman/listinfo/ipxe
|
||||
Please send support questions to the iPXE mailing list
|
||||
|
||||
System Requirements
|
||||
-------------------
|
||||
- Apache web server
|
||||
- PHP 4+
|
||||
- Tools required to build iPXE installed on the server
|
||||
- gcc, mtools, syslinux, perl, etc.
|
||||
|
||||
Setup
|
||||
-----
|
||||
As distributed, it is expected that the rom-o-matic source code
|
||||
directory is in the contrib directory of a iPXE source distribution.
|
||||
|
||||
The easiest way to do this is to simply put a iPXE source distribution
|
||||
in a web server accessible directory.
|
||||
|
||||
If this is not the case, you will need to either edit the file
|
||||
|
||||
"globals.php"
|
||||
|
||||
or create a file called
|
||||
|
||||
"local-config.php"
|
||||
|
||||
containing the following lines:
|
||||
|
||||
<?php
|
||||
$src_dir = "../../src";
|
||||
?>
|
||||
|
||||
Then change the line beginning "$src_dir = " to the path of your iPXE
|
||||
source code tree.
|
||||
|
||||
To make build times shorter, before you run rom-o-matic for the first time
|
||||
you should cd to the ipxe "src" directory and enter the following
|
||||
commands:
|
||||
|
||||
$ make
|
||||
$ make bin/NIC
|
||||
|
||||
This will pro-compile most object files and will make your rom-o-matic
|
||||
builds much faster.
|
||||
|
||||
Running rom-o-matic from a web browser
|
||||
--------------------------------------
|
||||
Enter a URL like:
|
||||
|
||||
http://example.com/ipxe-1.x.x/contrib/rom-o-matic
|
||||
|
||||
@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
?>
|
||||
<hr>
|
||||
<h4>
|
||||
Resources:
|
||||
</h4>
|
||||
<ul>
|
||||
<li>
|
||||
Source code for iPXE images is available at
|
||||
<a href="http://www.ipxe.org/download" target="_blank">
|
||||
http://www.ipxe.org/download</a>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
For general information about using iPXE, please visit the
|
||||
<a href="http://www.ipxe.org/" target="_blank">
|
||||
iPXE Project Home Page</a>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
For Email-based support for iPXE please join
|
||||
<a href="http://www.ipxe.org/contact" target="_blank">
|
||||
iPXE Project mailing lists.</a>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
For real-time online iPXE support via IRC please visit the
|
||||
<a href="irc://irc.freenode.net/%23ipxe"> #ipxe channel
|
||||
of irc.freenode.net</a>.
|
||||
<br><br>
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<font size="-1">
|
||||
<br>
|
||||
Please email <a href="mailto:<?php echo "${webmaster_email}" ?>"><?php echo "${webmaster_email}"?></a>
|
||||
with questions or comments about this website.
|
||||
</font>
|
||||
<br><br>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,311 +0,0 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
// Get utility functions and set globals
|
||||
require_once "utils.php";
|
||||
|
||||
// Make sure at least $A (action) was supplied
|
||||
if ( ! isset ( $_POST['A'] ) ) {
|
||||
|
||||
// Present user with form to customize build options
|
||||
require_once "customize-flags.php";
|
||||
|
||||
exit ();
|
||||
|
||||
// If user chose "Customize" option on form
|
||||
} else if ( $_POST['A'] == "Customize" ) {
|
||||
|
||||
// Present user with form to customize build options
|
||||
require_once "customize-flags.php";
|
||||
|
||||
exit ();
|
||||
|
||||
// The following conditional includes all other cases except "Get Image"
|
||||
// particularly the explicit ($A == "Start Over") case
|
||||
} else if ( $_POST['A'] != "Get Image" ) {
|
||||
|
||||
// Note that this method of redirections discards all the
|
||||
// configuration flags, which is intentional in this case.
|
||||
|
||||
$dest = curDirURL ();
|
||||
header ( "Location: $dest" );
|
||||
|
||||
// This next "echo" should normally not be seen, because
|
||||
// the "header" statement above should cause immediate
|
||||
// redirection but just in case...
|
||||
|
||||
echo "Try this link: <a href=\"$dest\">$dest</a>";
|
||||
|
||||
exit ();
|
||||
}
|
||||
|
||||
// OK, we're going to try to use whatever options have been set
|
||||
// to build an image.
|
||||
|
||||
// Make sure at least $nic was supplied
|
||||
if ( ! isset ( $_POST['nic'] ) ) {
|
||||
die ( "No NIC supplied!" );
|
||||
}
|
||||
if ( isset ( $nics[$_POST['nic']] ) ) {
|
||||
$nic = $nics[$_POST['nic']];
|
||||
} else {
|
||||
die ( "Invalid NIC \"${_POST['nic']}\" supplied!" );
|
||||
}
|
||||
|
||||
// Fetch flags
|
||||
$flags = get_flags ();
|
||||
|
||||
// Get requested format
|
||||
$ofmt = isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "";
|
||||
$fmt_extension = isset ( $ofmts[$ofmt] ) ? $ofmts[$ofmt] : 'dsk';
|
||||
|
||||
// Handle some special cases
|
||||
|
||||
$pci_vendor_code = "";
|
||||
$pci_device_code = "";
|
||||
|
||||
if ( $nic == 'undionly' && $fmt_extension == "pxe" ) {
|
||||
|
||||
// undionly.pxe can't work because it unloads the PXE stack
|
||||
// that it needs to communicate with, so we set the extension
|
||||
// to .kpxe, which has a chance of working. The extension
|
||||
// .kkpxe is another option.
|
||||
|
||||
$fmt_extension = "kpxe";
|
||||
|
||||
} else if ( $fmt_extension == "rom" ) {
|
||||
|
||||
if ( ! isset ( $_POST['pci_vendor_code'] )
|
||||
|| ! isset ( $_POST['pci_device_code'] ) ) {
|
||||
die ( "rom output format selected but PCI code(s) missing!" );
|
||||
}
|
||||
|
||||
$pci_vendor_code = $_POST['pci_vendor_code'];
|
||||
$pci_device_code = $_POST['pci_device_code'];
|
||||
|
||||
if ( $pci_vendor_code == ""
|
||||
|| $pci_device_code == "" ) {
|
||||
die ( "rom output format selected but PCI code(s) missing!" );
|
||||
}
|
||||
|
||||
// Try to be forgiving of 0xAAAA format
|
||||
if ( strtolower ( substr ( $pci_vendor_code, 0, 2 ) ) == "0x"
|
||||
&& strlen ( $pci_vendor_code ) == 6 ) {
|
||||
$pci_vendor_code = substr ( $pci_vendor_code, 2, 4 );
|
||||
}
|
||||
if ( strtolower ( substr ( $pci_device_code, 0, 2 ) ) == "0x"
|
||||
&& strlen ( $pci_device_code ) == 6 ) {
|
||||
$pci_device_code = substr ( $pci_device_code, 2, 4 );
|
||||
}
|
||||
|
||||
// concatenate the pci codes to get the $nic part of the
|
||||
// Make target
|
||||
$pci_codes = strtolower ( $pci_vendor_code . $pci_device_code );
|
||||
|
||||
$nic = $pci_codes;
|
||||
if ( ! isset ( $roms[$pci_codes] ) ) {
|
||||
die ( "Sorry, no network driver supports PCI codes<br>"
|
||||
. "${_POST['pci_vendor_code']}:"
|
||||
. "${_POST['pci_device_code']}" );
|
||||
}
|
||||
} else if ( $fmt_extension != "rom"
|
||||
&& ( $pci_vendor_code != "" || $pci_device_code != "" ) ) {
|
||||
die ( "'$fmt_extension' format was selected but PCI IDs were"
|
||||
. " also entered.<br>Did you mean to select 'rom' output format"
|
||||
. " instead?" );
|
||||
}
|
||||
|
||||
/**
|
||||
* remove temporary build directory
|
||||
*
|
||||
* @return bool true if removal is successful, false otherwise
|
||||
*/
|
||||
function rm_build_dir ()
|
||||
{
|
||||
global $build_dir;
|
||||
global $keep_build_dir;
|
||||
|
||||
if ( $keep_build_dir !== true ) {
|
||||
rm_file_or_dir ( $build_dir );
|
||||
}
|
||||
}
|
||||
|
||||
// Arrange for the build directory to always be removed on exit.
|
||||
$build_dir = "";
|
||||
$keep_build_dir = false;
|
||||
register_shutdown_function ( 'rm_build_dir' );
|
||||
|
||||
// Make temporary copy of src directory
|
||||
$build_dir = mktempcopy ( "$src_dir", "/tmp", "MDCROM" );
|
||||
$config_dir = $build_dir . "/config";
|
||||
|
||||
// Write config files with supplied flags
|
||||
write_ipxe_config_files ( $config_dir, $flags );
|
||||
|
||||
// Handle a possible embedded script
|
||||
$emb_script_cmd = "";
|
||||
$embedded_script = isset ( $_POST['embedded_script'] ) ? $_POST['embedded_script'] : "";
|
||||
if ( $embedded_script != "" ) {
|
||||
$emb_script_path = "$build_dir" . "/script0.ipxe";
|
||||
|
||||
if ( substr ( $embedded_script, 0, 5 ) != "#!ipxe" ) {
|
||||
$embedded_script = "#!ipxe\n" . $embedded_script;
|
||||
}
|
||||
|
||||
// iPXE 0.9.7 doesn't like '\r\n" in the shebang...
|
||||
$embedded_script = str_replace ( "\r\n", "\n", $embedded_script );
|
||||
|
||||
write_file_from_string ( $emb_script_path, $embedded_script );
|
||||
$emb_script_cmd = "EMBEDDED_IMAGE=${emb_script_path}";
|
||||
}
|
||||
|
||||
// Make the requested image. $status is set to 0 on success
|
||||
$make_target = "bin/${nic}.${fmt_extension}";
|
||||
$gitversion = exec('git describe --always --abbrev=1 --match "" 2>/dev/null');
|
||||
if ($gitversion) {
|
||||
$gitversion = "GITVERSION=$gitversion";
|
||||
}
|
||||
|
||||
$make_cmd = "make -C '$build_dir' '$make_target' $gitversion $emb_script_cmd 2>&1";
|
||||
|
||||
exec ( $make_cmd, $maketxt, $status );
|
||||
|
||||
// Uncomment the following section for debugging
|
||||
|
||||
/**
|
||||
|
||||
echo "<h2>build.php:</h2>";
|
||||
echo "<h3>Begin debugging output</h3>";
|
||||
|
||||
//echo "<h3>\$_POST variables</h3>";
|
||||
//echo "<pre>"; var_dump ( $_POST ); echo "</pre>";
|
||||
|
||||
echo "<h3>Build options:</h3>";
|
||||
echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
|
||||
echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
|
||||
echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" . "<br>";
|
||||
echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
|
||||
echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
|
||||
|
||||
echo "<h3>Flags:</h3>";
|
||||
show_flags ( $flags );
|
||||
|
||||
if ( $embedded_script != "" ) {
|
||||
echo "<h3>Embedded script:</h3>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo $embedded_script;
|
||||
echo "</pre>"."</blockquote>";
|
||||
}
|
||||
|
||||
echo "<h3>Make output:</h3>";
|
||||
echo "Make command: " . $make_cmd . "<br>";
|
||||
echo "Build status = <? echo $status ?>" . "<br>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo htmlentities ( implode ("\n", $maketxt ) );
|
||||
echo "</pre>"."</blockquote>";
|
||||
// Uncomment the next line if you want to keep the
|
||||
// build directory around for inspection after building.
|
||||
$keep_build_dir = true;
|
||||
die ( "<h3>End debugging output</h3>" );
|
||||
|
||||
**/ // End debugging section
|
||||
|
||||
// Send ROM to browser (with extreme prejudice)
|
||||
|
||||
if ( $status == 0 ) {
|
||||
|
||||
$fp = fopen("${build_dir}/${make_target}", "rb" );
|
||||
if ( $fp > 0 ) {
|
||||
|
||||
$len = filesize ( "${build_dir}/${make_target}" );
|
||||
if ( $len > 0 ) {
|
||||
|
||||
$buf = fread ( $fp, $len );
|
||||
fclose ( $fp );
|
||||
|
||||
// Delete build directory as soon as it is not needed
|
||||
rm_build_dir ();
|
||||
|
||||
$output_filename = preg_replace('/[^a-z0-9\+\.\-]/i', '', "ipxe-${version}-${nic}.${fmt_extension}");
|
||||
|
||||
// Try to force IE to handle downloading right.
|
||||
Header ( "Cache-control: private");
|
||||
Header ( "Content-Type: application/x-octet-stream; " .
|
||||
"name=$output_filename");
|
||||
Header ( "Content-Disposition: attachment; " .
|
||||
"Filename=$output_filename");
|
||||
Header ( "Content-Location: $output_filename");
|
||||
Header ( "Content-Length: $len");
|
||||
|
||||
echo $buf;
|
||||
|
||||
exit ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we reach this point, the build has failed, and we provide
|
||||
* debugging information for a potential bug report
|
||||
*
|
||||
*/
|
||||
|
||||
// Remove build directory
|
||||
rm_build_dir ();
|
||||
|
||||
// Announce failure if $status from make was non-zero
|
||||
echo "<h2>Build failed. Status = " . $status . "</h2>";
|
||||
echo "<h2>build.php:</h2>";
|
||||
echo "<h3>Build options:</h3>";
|
||||
echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
|
||||
echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
|
||||
echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" . "<br>";
|
||||
echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
|
||||
echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
|
||||
|
||||
echo "<h3>Flags:</h3>";
|
||||
show_flags ( $flags );
|
||||
|
||||
if ( $embedded_script != "" ) {
|
||||
echo "<h3>Embedded script:</h3>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo $embedded_script;
|
||||
echo "</pre>"."</blockquote>";
|
||||
}
|
||||
|
||||
echo "<h3>Make output:</h3>";
|
||||
echo "Make command: " . $make_cmd . "<br>";
|
||||
echo "<blockquote>"."<pre>";
|
||||
echo htmlentities ( implode ("\n", $maketxt ) );
|
||||
echo "</pre>"."</blockquote>";
|
||||
|
||||
echo "Please let us know that this happened, and paste the above output into your email message.<br>";
|
||||
|
||||
include_once $bottom_inc;
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
||||
@ -1,69 +0,0 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
// Get utility functions and set globals
|
||||
require_once "utils.php";
|
||||
|
||||
// Prepare settable compile options for presentation to user
|
||||
$flags = default_flags ();
|
||||
|
||||
$build = "<input type=\"submit\" name=\"A\" value=\"Get Image\">";
|
||||
$restart = "<input type=\"submit\" name=\"A\" value=\"Start Over\">";
|
||||
|
||||
// Begin html output
|
||||
include_once $top_inc;
|
||||
|
||||
?>
|
||||
|
||||
<form action="build.php" method=POST>
|
||||
<input type="hidden" name="version" value = "<?php echo $version ?>">
|
||||
<input type="hidden" name="use_flags" value="1">
|
||||
<h3>
|
||||
Make changes below and press <?php echo $build ?> to create an image, <br>
|
||||
Or press <?php echo $restart ?> to return to the main page.
|
||||
</h3>
|
||||
<hr>
|
||||
<ul>
|
||||
<?php require ( "directions.php" ); ?>
|
||||
</ul>
|
||||
<hr>
|
||||
<?php echo_flags( $flags ); ?>
|
||||
<hr>
|
||||
<h3>Embedded Script:</h3>
|
||||
<?php echo textarea ( "embedded_script", "", "10", "50" ); ?>
|
||||
<br><br>
|
||||
<hr>
|
||||
<center><table width="35%"><tr>
|
||||
<td align="left"> <?php echo $build; ?> </td>
|
||||
<td align="right"> <?php echo $restart ?></td>
|
||||
</tr></table></center>
|
||||
</form>
|
||||
|
||||
<?php include_once $bottom_inc; ?>
|
||||
<?
|
||||
// For emacs:
|
||||
//
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
?>
|
||||
@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
?>
|
||||
<li>
|
||||
Choose an output format: <?php echo keys_menubox ( "ofmt", $ofmts,
|
||||
isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "") ?>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
Choose a NIC type: <?php echo keys_menubox ( "nic", $nics,
|
||||
isset ( $_POST['nic'] ) ? $_POST['nic'] : "" ) ?>
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
<strong>( optional — for binary ROM image format only )</strong> <br><br>
|
||||
If you choose <em>Binary ROM image</em> as your output format, you must<br>
|
||||
enter <strong>4 hex digits</strong> below for
|
||||
<em>PCI VENDOR CODE</em> and <em>PCI DEVICE CODE</em> <br>
|
||||
that match the NIC device for which you are making this image.<br><br>
|
||||
Information on how to determine NIC PCI IDs may be found
|
||||
<a href="http://www.ipxe.org/howto/romburning"
|
||||
target="_blank">here</a>.
|
||||
<br><br>
|
||||
PCI VENDOR CODE: <?php echo textbox ( "pci_vendor_code",
|
||||
isset ( $_POST['pci_vendor_code'] ) ? $_POST['pci_vendor_code']
|
||||
: "", 6 ); ?>
|
||||
|
||||
PCI DEVICE CODE: <?php echo textbox ( "pci_device_code",
|
||||
isset ( $_POST['pci_device_code'] ) ? $_POST['pci_device_code']
|
||||
: "", 6 ); ?>
|
||||
<h4>Please note for ROM images:</h4>
|
||||
<ul>
|
||||
<li>
|
||||
If you enter PCI IDs, we will attempt to determine the correct<br>
|
||||
driver to support them, and will ignore any NIC type entered
|
||||
above.<br><br>
|
||||
</li>
|
||||
<li>
|
||||
iPXE does not support all possible PCI IDs for supported
|
||||
NICs.
|
||||
<br><br>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
@ -1 +0,0 @@
|
||||
Automatic booting
|
||||
@ -1 +0,0 @@
|
||||
Tenths of a second for which the shell banner should appear
|
||||
@ -1,3 +0,0 @@
|
||||
Serial Console I/O port address. Common addresses are:<br>
|
||||
COM1 => 0x3f8, COM2 => 0x2f8, COM3 => 0x3e8, COM4 => 0x2e8
|
||||
|
||||
@ -1 +0,0 @@
|
||||
Serial Console Data bits
|
||||
@ -1 +0,0 @@
|
||||
Serial Console Parity: 0=None, 1=Odd, 2=Even
|
||||
@ -1 +0,0 @@
|
||||
Keep settings from a previous user of the serial port
|
||||
@ -1 +0,0 @@
|
||||
Serial Console Baud rate
|
||||
@ -1 +0,0 @@
|
||||
Serial Console Stop bits
|
||||
@ -1 +0,0 @@
|
||||
Option configuration console
|
||||
@ -1 +0,0 @@
|
||||
Enable Default BIOS console
|
||||
@ -1 +0,0 @@
|
||||
Enable Serial port console
|
||||
@ -1 +0,0 @@
|
||||
Wireless WEP encryption support
|
||||
@ -1 +0,0 @@
|
||||
Wireless WPA encryption support
|
||||
@ -1 +0,0 @@
|
||||
Wireless WPA2 encryption support
|
||||
@ -1 +0,0 @@
|
||||
DHCP management commands
|
||||
@ -1 +0,0 @@
|
||||
DNS resolver
|
||||
@ -1 +0,0 @@
|
||||
File Transfer Protocol
|
||||
@ -1 +0,0 @@
|
||||
Hypertext Transfer Protocol
|
||||
@ -1 +0,0 @@
|
||||
Trivial File Transfer Protocol
|
||||
@ -1 +0,0 @@
|
||||
Interface management commands
|
||||
@ -1 +0,0 @@
|
||||
Linux bzImage image support
|
||||
@ -1 +0,0 @@
|
||||
Image management commands
|
||||
@ -1 +0,0 @@
|
||||
ELF image support
|
||||
@ -1 +0,0 @@
|
||||
MultiBoot image support
|
||||
@ -1 +0,0 @@
|
||||
NBI image support
|
||||
@ -1 +0,0 @@
|
||||
PXE image support
|
||||
@ -1 +0,0 @@
|
||||
iPXE script image support
|
||||
@ -1 +0,0 @@
|
||||
Wireless interface management commands
|
||||
@ -1 +0,0 @@
|
||||
NMB resolver
|
||||
@ -1 +0,0 @@
|
||||
Non-volatile option storage commands
|
||||
@ -1 +0,0 @@
|
||||
Routing table management commands
|
||||
@ -1 +0,0 @@
|
||||
SAN boot commands
|
||||
@ -1,531 +0,0 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
$ofmts = array
|
||||
( "Floppy bootable image (.dsk)" => "dsk",
|
||||
"SYSLINUX-based bootable floppy image (.sdsk)" => "sdsk",
|
||||
"ISO bootable image (.iso)" => "iso",
|
||||
"ISO bootable image with legacy floppy emulation (.liso)" => "liso",
|
||||
"Linux kernel (SYSLINUX/GRUB/LILO) loadable image (.lkrn)" => "lkrn",
|
||||
"USB Keychain disk image (.usb)" => "usb",
|
||||
"ROM binary (flashable) image (.rom)" => "rom",
|
||||
"ROM binary (flashable) for problem PMM BIOSES (.hrom)" => "hrom",
|
||||
"PXE bootstrap loader image [Unload PXE stack] (.pxe)" => "pxe",
|
||||
"PXE bootstrap loader keep [Keep PXE stack method 1] (.kpxe)" => "kpxe",
|
||||
"PXE bootstrap loader keep [Keep PXE stack method 2] (.kkpxe)" => "kkpxe",
|
||||
);
|
||||
|
||||
$flag_table = array (
|
||||
|
||||
// Begin General Options:
|
||||
|
||||
"HDR_MISC_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_MISC_OPTIONS",
|
||||
"hide_from_user" => "yes", // Hide even the header
|
||||
"type" => "header",
|
||||
"label" => "Miscellaneous Options"
|
||||
),
|
||||
|
||||
"PRODUCT_NAME"
|
||||
=> array (
|
||||
"flag" => "PRODUCT_NAME",
|
||||
"hide_from_user" => "yes",
|
||||
"type" => "string",
|
||||
"value" => "",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"PRODUCT_SHORT_NAME"
|
||||
=> array (
|
||||
"flag" => "PRODUCT_SHORT_NAME",
|
||||
"hide_from_user" => "yes",
|
||||
"type" => "string",
|
||||
"value" => "iPXE",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End General Options:
|
||||
|
||||
// Begin Console Options:
|
||||
|
||||
"HDR_CONSOLE_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_CONSOLE_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Console Options"
|
||||
),
|
||||
|
||||
"CONSOLE_PCBIOS"
|
||||
=> array (
|
||||
"flag" => "CONSOLE_PCBIOS",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
"CONSOLE_SERIAL"
|
||||
=> array (
|
||||
"flag" => "CONSOLE_SERIAL",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
"BANNER_TIMEOUT"
|
||||
=> array (
|
||||
"flag" => "BANNER_TIMEOUT",
|
||||
"type" => "integer",
|
||||
"value" => "20",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"KEYBOARD_MAP"
|
||||
=> array (
|
||||
"flag" => "KEYBOARD_MAP",
|
||||
"type" => "choice",
|
||||
"options" => array("al","az","bg","by","cf","cz","de","dk","es","et","fi","fr",
|
||||
"gr","hu","il","it","lt","mk","mt","nl","no","pl","pt","ro","ru","sg","sr",
|
||||
"th","ua","uk","us","wo"),
|
||||
"value" => "us",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
"LOG_LEVEL"
|
||||
=> array (
|
||||
"flag" => "LOG_LEVEL",
|
||||
"type" => "choice",
|
||||
"options" => array("LOG_NONE","LOG_EMERG","LOG_ALERT","LOG_CRIT","LOG_ERR",
|
||||
"LOG_WARNING","LOG_NOTICE","LOG_INFO","LOG_DEBUG","LOG_ALL"),
|
||||
"value" => "LOG_NONE",
|
||||
"cfgsec" => "console"
|
||||
),
|
||||
|
||||
// End Console Options
|
||||
|
||||
// Begin Network Protocol Options:
|
||||
|
||||
"HDR_NETWORK_PROTOCOL_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_NETWORK_PROTOCOL_OPTIONS",
|
||||
"hide_from_user" => "yes", // Hide even the header
|
||||
"type" => "header",
|
||||
"label" => "Network Protocol Options"
|
||||
),
|
||||
|
||||
"NET_PROTO_IPV4"
|
||||
=> array (
|
||||
"flag" => "NET_PROTO_IPV4",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"hide_from_user" => "yes",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Network Protocol Options
|
||||
|
||||
// Begin Serial Port configuration
|
||||
|
||||
"HDR_SERIAL_PORT_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_SERIAL_PORT_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Serial Port Options"
|
||||
),
|
||||
|
||||
"COMCONSOLE"
|
||||
=> array (
|
||||
"flag" => "COMCONSOLE",
|
||||
"type" => "integer-hex", // e.g. 0x378
|
||||
"value" => "0x3F8",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMPRESERVE"
|
||||
=> array (
|
||||
"flag" => "COMPRESERVE",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMSPEED"
|
||||
=> array (
|
||||
"flag" => "COMSPEED",
|
||||
"type" => "integer",
|
||||
"value" => "115200",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMDATA"
|
||||
=> array (
|
||||
"flag" => "COMDATA",
|
||||
"type" => "integer",
|
||||
"value" => "8",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMPARITY"
|
||||
=> array (
|
||||
"flag" => "COMPARITY",
|
||||
"type" => "integer",
|
||||
"value" => "0",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
"COMSTOP"
|
||||
=> array (
|
||||
"flag" => "COMSTOP",
|
||||
"type" => "integer",
|
||||
"value" => "1",
|
||||
"cfgsec" => "serial"
|
||||
),
|
||||
|
||||
// End Serial Options
|
||||
|
||||
// Begin Download Protocols
|
||||
|
||||
"HDR_DOWNLOAD_PROTOCOLS"
|
||||
=> array (
|
||||
"flag" => "HDR_DOWNLOAD_PROTOCOLS",
|
||||
"type" => "header",
|
||||
"label" => "Download Protocols"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_TFTP"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_TFTP",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_HTTP"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_HTTP",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_HTTPS"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_HTTPS",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DOWNLOAD_PROTO_FTP"
|
||||
=> array (
|
||||
"flag" => "DOWNLOAD_PROTO_FTP",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Download Protocols
|
||||
|
||||
// Begin SAN boot protocols
|
||||
|
||||
"HDR_SANBOOT_PROTOCOLS"
|
||||
=> array (
|
||||
"flag" => "HDR_SANBOOT_PROTOCOLS",
|
||||
"type" => "header",
|
||||
"label" => "SAN Boot Protocols"
|
||||
),
|
||||
|
||||
"SANBOOT_PROTO_ISCSI"
|
||||
=> array (
|
||||
"flag" => "SANBOOT_PROTO_ISCSI",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"SANBOOT_PROTO_AOE"
|
||||
=> array (
|
||||
"flag" => "SANBOOT_PROTO_AOE",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End SAN boot protocols
|
||||
|
||||
// Begin Name resolution modules
|
||||
|
||||
"HDR_NAME_RESOLUTION_MODULES"
|
||||
=> array (
|
||||
"flag" => "HDR_NAME_RESOLUTION_MODULES",
|
||||
"type" => "header",
|
||||
"label" => "Name Resolution Modules"
|
||||
),
|
||||
|
||||
"DNS_RESOLVER"
|
||||
=> array (
|
||||
"flag" => "DNS_RESOLVER",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"NMB_RESOLVER"
|
||||
=> array (
|
||||
"flag" => "NMB_RESOLVER",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"hide_from_user" => "yes",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Name resolution modules
|
||||
|
||||
// Begin Image types
|
||||
|
||||
"HDR_IMAGE_TYPES"
|
||||
=> array (
|
||||
"flag" => "HDR_IMAGE_TYPES",
|
||||
"type" => "header",
|
||||
"label" => "Image Types",
|
||||
),
|
||||
|
||||
"IMAGE_ELF"
|
||||
=> array (
|
||||
"flag" => "IMAGE_ELF",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_NBI"
|
||||
=> array (
|
||||
"flag" => "IMAGE_NBI",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_MULTIBOOT"
|
||||
=> array (
|
||||
"flag" => "IMAGE_MULTIBOOT",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_PXE"
|
||||
=> array (
|
||||
"flag" => "IMAGE_PXE",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_SCRIPT"
|
||||
=> array (
|
||||
"flag" => "IMAGE_SCRIPT",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_BZIMAGE"
|
||||
=> array (
|
||||
"flag" => "IMAGE_BZIMAGE",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_COMBOOT"
|
||||
=> array (
|
||||
"flag" => "IMAGE_COMBOOT",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Image types
|
||||
|
||||
// Begin Command-line commands to include
|
||||
|
||||
"HDR_COMMAND_LINE_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_COMMAND_LINE_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Command Line Options",
|
||||
),
|
||||
|
||||
"AUTOBOOT_CMD"
|
||||
=> array (
|
||||
"flag" => "AUTOBOOT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"NVO_CMD"
|
||||
=> array (
|
||||
"flag" => "NVO_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"CONFIG_CMD"
|
||||
=> array (
|
||||
"flag" => "CONFIG_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IFMGMT_CMD"
|
||||
=> array (
|
||||
"flag" => "IFMGMT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IWMGMT_CMD"
|
||||
=> array (
|
||||
"flag" => "IWMGMT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"ROUTE_CMD"
|
||||
=> array (
|
||||
"flag" => "ROUTE_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"IMAGE_CMD"
|
||||
=> array (
|
||||
"flag" => "IMAGE_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DHCP_CMD"
|
||||
=> array (
|
||||
"flag" => "DHCP_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"SANBOOT_CMD"
|
||||
=> array (
|
||||
"flag" => "SANBOOT_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"LOGIN_CMD"
|
||||
=> array (
|
||||
"flag" => "LOGIN_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"TIME_CMD"
|
||||
=> array (
|
||||
"flag" => "TIME_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"DIGEST_CMD"
|
||||
=> array (
|
||||
"flag" => "DIGEST_CMD",
|
||||
"type" => "on/off",
|
||||
"value" => "off",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Command-line commands to include
|
||||
|
||||
// Begin Wireless options
|
||||
|
||||
"HDR_WIRELESS_OPTIONS"
|
||||
=> array (
|
||||
"flag" => "HDR_WIRELESS_OPTIONS",
|
||||
"type" => "header",
|
||||
"label" => "Wireless Interface Options",
|
||||
),
|
||||
|
||||
"CRYPTO_80211_WEP"
|
||||
=> array (
|
||||
"flag" => "CRYPTO_80211_WEP",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"CRYPTO_80211_WPA"
|
||||
=> array (
|
||||
"flag" => "CRYPTO_80211_WPA",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
"CRYPTO_80211_WPA2"
|
||||
=> array (
|
||||
"flag" => "CRYPTO_80211_WPA2",
|
||||
"type" => "on/off",
|
||||
"value" => "on",
|
||||
"cfgsec" => "general"
|
||||
),
|
||||
|
||||
// End Wireless options
|
||||
|
||||
// Obscure options required to compile
|
||||
"NETDEV_DISCARD_RATE"
|
||||
=> array (
|
||||
"flag" => "NETDEV_DISCARD_RATE",
|
||||
"type" => "integer",
|
||||
"value" => "0",
|
||||
"cfgsec" => "general",
|
||||
"hide_from_user" => true
|
||||
)
|
||||
|
||||
// End Obscure options
|
||||
);
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
||||
@ -1,51 +0,0 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
// Directory containing iPXE source code tree
|
||||
$src_dir = "../../src";
|
||||
|
||||
// Compute iPXE version based on source tree
|
||||
exec ( "make -C '$src_dir' version 2>&1", $make_output, $status );
|
||||
$version = ( $status == 0 && count ( $make_output ) > 1 )
|
||||
? trim ( $make_output[count ( $make_output ) - 2] )
|
||||
: "";
|
||||
|
||||
// Email address of person responsible for this website
|
||||
$webmaster_email = "webmaster@example.com";
|
||||
|
||||
// Files that header and footer text
|
||||
$top_inc = "top.php";
|
||||
$bottom_inc = "bottom.php";
|
||||
|
||||
// Descriptive strings
|
||||
$header_title = "ROM-o-matic for iPXE $version";
|
||||
$html_tagline = "ROM-o-matic dynamically generates iPXE images";
|
||||
$html_title = "ROM-o-matic for iPXE $version";
|
||||
$description = "a dynamic iPXE image generator";
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
||||
@ -1,47 +0,0 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
// Get utility functions and set globals
|
||||
require_once "utils.php";
|
||||
|
||||
// Begin html output
|
||||
include_once $top_inc;
|
||||
|
||||
?>
|
||||
<form action="build.php" method=POST>
|
||||
<input type="hidden" name="version" value = "<?php echo $version ?>">
|
||||
<h3>To create an image:</h3>
|
||||
<ol>
|
||||
<?php require ( "directions.php" ); ?>
|
||||
<li>
|
||||
Generate and download an image:
|
||||
<input type="submit" name="A" value="Get Image">
|
||||
<br><br>
|
||||
</li>
|
||||
<li>
|
||||
(optional) Customize image configuration options:
|
||||
<input type="submit" name="A" value="Customize">
|
||||
<br><br>
|
||||
</li>
|
||||
</ol>
|
||||
</form>
|
||||
|
||||
<?php include_once $bottom_inc ?>
|
||||
@ -1,684 +0,0 @@
|
||||
<?php // -*- Mode: PHP; -*-
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
|
||||
* Copyright (C) 2009 Entity Cyber, Inc.
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
// Include table of user-configurable iPXE options
|
||||
require_once "flag-table.php";
|
||||
|
||||
// Include user-shadowable globals
|
||||
require_once "globals.php";
|
||||
|
||||
// Allow user to shadow globals
|
||||
if ( is_file ( 'local-config.php' ) ) {
|
||||
include_once "local-config.php";
|
||||
}
|
||||
|
||||
////
|
||||
// General utility functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Remove undesirable characters from a given string
|
||||
*
|
||||
* Certain characters have the potential to be used for
|
||||
* malicious purposes by web-based attackers. This routine
|
||||
* filters out such characters.
|
||||
*
|
||||
* @param string $s supplied string
|
||||
*
|
||||
* @return string returned string with unwanted characters
|
||||
* removed
|
||||
*/
|
||||
function cleanstring ( $s )
|
||||
{
|
||||
$len = strlen ( $s );
|
||||
if ( $len > 80 ) {
|
||||
$s = substr ( $s, 0, 80 );
|
||||
}
|
||||
|
||||
$s = trim ( $s );
|
||||
$pos = 0;
|
||||
$result = "";
|
||||
|
||||
while ( $pos < $len ) {
|
||||
$ltr = ord ( ucfirst ( $s[$pos] ) );
|
||||
if ( ( $ltr >= ord ( "A" ) ) && ( $ltr <= ord ( "Z" ) ) ||
|
||||
( $ltr >= ord ( "0" ) ) && ( $ltr <= ord ( "9" ) ) ||
|
||||
( $ltr == ord ( "." ) ) && ( strlen ( $result ) > 0 ) ||
|
||||
( $ltr == ord ( "_" ) ) ||
|
||||
( $ltr == ord ( "+" ) ) ||
|
||||
( $ltr == ord ( ":" ) ) ||
|
||||
( $ltr == ord ( "/" ) ) ||
|
||||
( $ltr == ord ( "-" ) ) ) {
|
||||
$result .= $s[$pos];
|
||||
}
|
||||
$pos++;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return URL of the currently running script, minus the filename
|
||||
*
|
||||
* @return string the URL of the currently running script, minus the filename
|
||||
*/
|
||||
function curDirURL ()
|
||||
{
|
||||
$dir = dirname ( $_SERVER['PHP_SELF'] );
|
||||
|
||||
if ( $dir == "." || $dir == "/" ) {
|
||||
$dir = "";
|
||||
}
|
||||
|
||||
$isHTTPS = ( isset ( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" );
|
||||
$port = ( isset($_SERVER["SERVER_PORT"] ) &&
|
||||
( ( !$isHTTPS && $_SERVER["SERVER_PORT"] != "80" ) ||
|
||||
( $isHTTPS && $_SERVER["SERVER_PORT"] != "443" ) ) );
|
||||
|
||||
$port = ( $port ) ? ':' . $_SERVER["SERVER_PORT"] : '';
|
||||
|
||||
$dest = ( $isHTTPS ? 'https://' : 'http://' ) .
|
||||
$_SERVER["SERVER_NAME"] . $dir . "/";
|
||||
|
||||
return $dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file.
|
||||
*
|
||||
* $src_dir must contain the path of the iPXE src directory for this build
|
||||
*
|
||||
* @return array[0] array $new_nics
|
||||
* @return array[1] array $roms
|
||||
*/
|
||||
function parse_nic_file ()
|
||||
{
|
||||
global $src_dir;
|
||||
|
||||
$fd = fopen ( "$src_dir/bin/NIC", "r" );
|
||||
if ( ! $fd ) {
|
||||
die ( "Missing src/bin/NIC file. 'make bin/NIC'" );
|
||||
}
|
||||
|
||||
$nics = array ();
|
||||
$roms = array ();
|
||||
$nic = "";
|
||||
|
||||
while ( !feof ( $fd ) ) {
|
||||
|
||||
$line = trim ( fgets ( $fd, 200 ) );
|
||||
|
||||
$first_eight_chars = substr ( $line, 0, 8 );
|
||||
settype ( $first_eight_chars, "string" );
|
||||
|
||||
if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
|
||||
|
||||
// get pathname of NIC driver
|
||||
#list ( $dummy, $nic ) = split( "[ \t]+", $line );
|
||||
list ( $dummy, $nic ) = explode("\t", $line);
|
||||
settype ( $nic, "string" );
|
||||
|
||||
// extract filename name of driver from pathname
|
||||
$nic = substr ( $nic, strrpos ( $nic, "/" ) + 1,
|
||||
strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 );
|
||||
|
||||
$nics[$nic] = $nic;
|
||||
|
||||
// For each ISA NIC, there can only be one ROM variant
|
||||
$roms[$nic] = $nic;
|
||||
}
|
||||
|
||||
// If the first 8 digits of the line are hex digits
|
||||
// add this rom to the current nic family.
|
||||
|
||||
if ( ( strlen ( $first_eight_chars ) == 8 )
|
||||
&& ( ctype_xdigit ( $first_eight_chars ) )
|
||||
&& ( $nic != "" ) ) {
|
||||
|
||||
$roms[$first_eight_chars] = $nic;
|
||||
}
|
||||
}
|
||||
fclose ( $fd );
|
||||
|
||||
// put most NICs in nice alpha order for menu
|
||||
ksort ( $nics );
|
||||
|
||||
// add special cases to the top
|
||||
|
||||
$new_nics = array ( "all-drivers" => "ipxe",
|
||||
"undionly" => "undionly",
|
||||
"undi" => "undi",
|
||||
);
|
||||
|
||||
foreach ( $nics as $key => $value ) {
|
||||
// skip the undi driver
|
||||
if ( $key != "undi" ) {
|
||||
$new_nics[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return array ( $new_nics, $roms );
|
||||
}
|
||||
|
||||
////
|
||||
// HTML form utility functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Return html code to create hidden form input fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value value to give form variable
|
||||
*
|
||||
* @return string html code for given hidden form input field
|
||||
*/
|
||||
function hidden ( $flag, $value )
|
||||
{
|
||||
$value = htmlentities ( $value );
|
||||
return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create checkbox form input fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value "on" means box should be checked
|
||||
*
|
||||
* @return string html code for given hidden form input field
|
||||
*/
|
||||
function checkbox ( $flag, $value )
|
||||
{
|
||||
return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" .
|
||||
($value == "on" ? " checked>" : ">" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create text form input fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value initial contents of field
|
||||
* @param string $size size in characters of text box
|
||||
*
|
||||
* @return string html code for given text input field
|
||||
*/
|
||||
function textbox ( $flag, $value, $size )
|
||||
{
|
||||
$value = htmlentities ( $value );
|
||||
return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create textarea form fields
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param string $value initial contents of textarea
|
||||
* @param string $rows height of text area in rows
|
||||
* @param string $cols width of text area in columns
|
||||
*
|
||||
* @return string html code for given textarea input field
|
||||
*/
|
||||
function textarea ( $flag, $value, $rows, $cols )
|
||||
{
|
||||
$value = htmlentities ( $value );
|
||||
return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">"
|
||||
. $value . "</textarea>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create select (menu) form fields
|
||||
*
|
||||
* Use array of strings as menu choices
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param array $options array of strings representing choices
|
||||
* @param string $value value of choice to select in menu
|
||||
*
|
||||
* @return string html code for given select (menu) input field
|
||||
*/
|
||||
function menubox ( $name, $options, $value )
|
||||
{
|
||||
$s="<select name=\"$name\">";
|
||||
|
||||
foreach ( $options as $ignore => $option ) {
|
||||
if ( !$value ) $value = $option;
|
||||
$s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
|
||||
htmlentities ( $option ) . "</option>";
|
||||
}
|
||||
return $s . "</select>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return html code to create select (menu) form fields
|
||||
*
|
||||
* Use indices of array of strings as menu choices rather than
|
||||
* the values pointed to by the indicies.
|
||||
*
|
||||
* @param string $flag name of form variable to set
|
||||
* @param array $options array of strings representing choices
|
||||
* @param string $value value of choice to select in menu
|
||||
*
|
||||
* @return string html code for given select (menu) input field
|
||||
*/
|
||||
function keys_menubox ( $name, $options, $value )
|
||||
{
|
||||
$s="<select name=\"$name\">";
|
||||
|
||||
foreach ( $options as $option => $ignore ) {
|
||||
if ( !$value ) $value = $option;
|
||||
$s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
|
||||
htmlentities ( $option ) . "</option>";
|
||||
}
|
||||
return $s . "</select>";
|
||||
}
|
||||
|
||||
////
|
||||
// Flag (compile option) handling functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Return default compile options (flags)
|
||||
*
|
||||
* Initial compile options are in a global called $flag_table.
|
||||
* Create and return an array containing the ones we want.
|
||||
*
|
||||
* @return array default compile options (flags)
|
||||
*/
|
||||
function default_flags ()
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
$flags = array ();
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
|
||||
$flag = $props["flag"];
|
||||
$type = $props["type"];
|
||||
|
||||
// Fields like headers have no "value" property
|
||||
if ( isset ( $props["value"] ) ) {
|
||||
$flags[$flag] = $props["value"];
|
||||
}
|
||||
}
|
||||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return combination of default and user compile options (flags)
|
||||
*
|
||||
* Initial compile options are in a global called $flag_table.
|
||||
* Compile options may have been changed via form input. We return
|
||||
* an array with either the default value of each option or a user
|
||||
* supplied value from form input.
|
||||
*
|
||||
* @return array combined default and user supplied compile options (flags)
|
||||
*/
|
||||
function get_flags ()
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
$flags = default_flags ();
|
||||
|
||||
if ( ! isset ( $_POST["use_flags"] ) )
|
||||
return $flags;
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
|
||||
$flag = $props["flag"];
|
||||
$type = $props["type"];
|
||||
|
||||
if ( isset ( $_POST["$flag"] ) ) {
|
||||
$flags[$flag] = $_POST["$flag"];
|
||||
if ( $type == "integer-hex" ) {
|
||||
if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) {
|
||||
$flags[$flag] = "0x" . $flags[$flag];
|
||||
}
|
||||
}
|
||||
} else if ( $type == "on/off" ) {
|
||||
// Unchecked checkboxes don't pass any POST value
|
||||
// so we must check for them specially. At this
|
||||
// point we know that there is no $_POST value set
|
||||
// for this option. If it is a checkbox, this means
|
||||
// it is unchecked, so record that in $flags so we
|
||||
// can later generate an #undef for this option.
|
||||
$flags[$flag] = "off";
|
||||
}
|
||||
}
|
||||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output given value in appropriate format for iPXE config file
|
||||
*
|
||||
* iPXE config/*.h files use C pre-processor syntax. Output the given
|
||||
* compile option in a format appropriate to its type
|
||||
*
|
||||
* @param string $key index into $flag_table for given compile option
|
||||
* @param string $value value we wish to set compile option to
|
||||
*
|
||||
* @return string code to set compile option to given value
|
||||
*/
|
||||
function pprint_flag ( $key, $value )
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
// Determine type of given compile option (flag)
|
||||
$type = $flag_table[$key]["type"];
|
||||
$s = "";
|
||||
|
||||
if ( $type == "on/off" && $value == "on" ) {
|
||||
$s = "#define $key";
|
||||
} else if ( $type == "on/off" && $value != "on" ) {
|
||||
$s = "#undef $key";
|
||||
} else if ( $type == "string" ) {
|
||||
$s = ( "#define $key \"" . cleanstring ( $value ) . "\"" );
|
||||
} else if ($type == "qstring" ) {
|
||||
$s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" );
|
||||
} else {
|
||||
$s = "#define $key " . cleanstring ( $value );
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output html code to display all compile options as a table
|
||||
*
|
||||
* @param array $flags array of compile options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function echo_flags ( $flags )
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
echo "<table>\n";
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
|
||||
// Hide parameters from users that should not be changed.
|
||||
$hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no";
|
||||
|
||||
$flag = $props["flag"];
|
||||
$type = $props["type"];
|
||||
|
||||
$value = isset ( $flags[$flag] ) ? $flags[$flag] : '';
|
||||
|
||||
if ( $hide_from_user == "yes" ) {
|
||||
|
||||
// Hidden flags cannot not be set by the user. We use hidden form
|
||||
// fields to keep them at their default values.
|
||||
if ( $type != "header" ) {
|
||||
echo hidden ( $flag, $value );
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Flag (iPXE compile option) should be displayed to user
|
||||
|
||||
if ( $type == "header" ) {
|
||||
|
||||
$label = $props["label"];
|
||||
echo "<td colspan=2><hr><h3>$label</h3><hr></td>";
|
||||
|
||||
} else if ($type == "on/off" ) {
|
||||
|
||||
echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>";
|
||||
|
||||
} else { // don't display checkbox for non-on/off flags
|
||||
|
||||
echo "<td> </td><td><strong>$flag: </strong>";
|
||||
|
||||
if ($type == "choice" ) {
|
||||
$options = $props["options"];
|
||||
echo menubox($flag, $options, $value);
|
||||
|
||||
} else {
|
||||
|
||||
echo textbox($flag, $value, ($type == "integer" ||
|
||||
$type == "integer-hex"
|
||||
? 7 : 25));
|
||||
}
|
||||
echo "</td>";
|
||||
}
|
||||
echo "</tr>\n";
|
||||
|
||||
if ( $type != "header" ) {
|
||||
echo "<tr><td> </td>";
|
||||
echo "<td>\n";
|
||||
if ( is_file ( "doc/$flag.html" ) ) {
|
||||
include_once "doc/$flag.html";
|
||||
}
|
||||
echo "\n</td></tr>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "</table>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of configuration sections used in all compile options
|
||||
*
|
||||
* $flag_table, the global list of compile options contains a 'cfgsec'
|
||||
* property for each flag we are interested in. We return a list of
|
||||
* all the unique cfgsec options we find in $flag_table.
|
||||
*
|
||||
* @return array an array of strings representing all unique cfgsec values
|
||||
* found in $flag_table
|
||||
*/
|
||||
function get_flag_cfgsecs ()
|
||||
{
|
||||
global $flag_table;
|
||||
$cfgsecs = array ();
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
if ( isset ( $props['cfgsec'] ) ) {
|
||||
$cfgsec = $props["cfgsec"];
|
||||
$cfgsecs[$cfgsec] = $cfgsec;
|
||||
}
|
||||
}
|
||||
return $cfgsecs;
|
||||
}
|
||||
|
||||
////
|
||||
// File and directory handling functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Create a copy of a given source directory to a given destination
|
||||
*
|
||||
* Since we are going to modify the source directory, we create a copy
|
||||
* of the directory with a unique name in the given destination directory.
|
||||
* We supply a prefix for the tempnam call to prepend to the random filename
|
||||
* it generates.
|
||||
*
|
||||
* @param string $src source directory
|
||||
* @param string $dst destination directory
|
||||
* @param string $prefix string to append to directory created
|
||||
*
|
||||
* @return string absolute path to destination directory
|
||||
*/
|
||||
function mktempcopy ( $src, $dst, $prefix )
|
||||
{
|
||||
if ( $src[0] != "/" ) {
|
||||
$src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src;
|
||||
}
|
||||
|
||||
// Create a file in the given destination directory with a unique name
|
||||
$dir = tempnam ( $dst, $prefix );
|
||||
|
||||
// Delete the file just created, since it would interfere with the copy we
|
||||
// are about to do. We only care that the dir name we copy to is unique.
|
||||
unlink ( $dir );
|
||||
|
||||
exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status );
|
||||
|
||||
if ( $status != 0 ) {
|
||||
die ( "src directory copy failed!" );
|
||||
}
|
||||
return $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write iPXE config files based on value of given flags
|
||||
*
|
||||
* iPXE compile options are stored in src/config/*.h .
|
||||
* We write out a config file for each set of options.
|
||||
*
|
||||
* @param string $config_dir directory to write .h files to
|
||||
* @param array $flags array of compile options for this build
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function write_ipxe_config_files ( $config_dir, $flags )
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
$cfgsecs = get_flag_cfgsecs ();
|
||||
|
||||
foreach ( $cfgsecs as $cfgsec ) {
|
||||
|
||||
$fname = $config_dir . "/" . $cfgsec . ".h";
|
||||
|
||||
$fp = fopen ( $fname, "wb" );
|
||||
if ( $fp <= 0 ) {
|
||||
die ( "Unable to open $fname file for output!" );
|
||||
}
|
||||
|
||||
$ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H";
|
||||
|
||||
fwrite ( $fp, "#ifndef ${ifdef_secname}\n" );
|
||||
fwrite ( $fp, "#define ${ifdef_secname}\n" );
|
||||
fwrite ( $fp, "#include <config/defaults.h>\n" );
|
||||
|
||||
foreach ( $flags as $key => $value ) {
|
||||
// When the flag matches this section name, write it out
|
||||
if ( $flag_table[$key]["cfgsec"] == $cfgsec ) {
|
||||
fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" );
|
||||
}
|
||||
}
|
||||
fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" );
|
||||
fclose ( $fp );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a string to a file
|
||||
*
|
||||
* Output a given string to a given pathname. The file will be created if
|
||||
* necessary, and the string will replace the file's contents in all cases.
|
||||
*
|
||||
* @param string $fname pathname of file to output string to
|
||||
* @param string $ftext text to output to file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function write_file_from_string ( $fname, $ftext )
|
||||
{
|
||||
$fp = fopen ( $fname, "wb" );
|
||||
if ( ! $fp ) {
|
||||
die ( "Unable to open $fname file for output!" );
|
||||
}
|
||||
fwrite ( $fp, $ftext );
|
||||
fclose ( $fp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file or recursively delete a directory tree
|
||||
*
|
||||
* @param string $file_or_dir_name name of file or directory to delete
|
||||
* @return bool Returns TRUE on success, FALSE on failure
|
||||
*/
|
||||
function rm_file_or_dir ( $file_or_dir_name )
|
||||
{
|
||||
if ( ! file_exists ( $file_or_dir_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) {
|
||||
return unlink ( $file_or_dir_name );
|
||||
}
|
||||
|
||||
$dir = dir ( $file_or_dir_name );
|
||||
while ( ( $dir_entry = $dir->read () ) !== false ) {
|
||||
|
||||
if ( $dir_entry == '.' || $dir_entry == '..') {
|
||||
continue;
|
||||
}
|
||||
rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry );
|
||||
}
|
||||
$dir->close();
|
||||
|
||||
return rmdir ( $file_or_dir_name );
|
||||
}
|
||||
|
||||
////
|
||||
// Debugging functions
|
||||
////
|
||||
|
||||
/**
|
||||
* Emit html code to display given array of compile options (flags)
|
||||
*
|
||||
* @param array $flags array of compile options for this build
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function show_flags ( $flags )
|
||||
{
|
||||
echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" );
|
||||
|
||||
foreach ( $flags as $key => $flag ) {
|
||||
echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit HTML code to display default array of compile options (flags)
|
||||
*
|
||||
* $flag_table contains default compile options and properties. This
|
||||
* routine outputs HTML code to display all properties of $flag_table.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function dump_flag_table ()
|
||||
{
|
||||
global $flag_table;
|
||||
|
||||
echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" );
|
||||
|
||||
foreach ( $flag_table as $key => $props ) {
|
||||
print ( "flag_table[" . $key . "] = " . "<br>" );
|
||||
|
||||
foreach ( $props as $key2 => $props2 ) {
|
||||
print ( " " . $key2 . " = " . $props2 . "<br>" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse src/bin/NIC file
|
||||
list ( $nics, $roms ) = parse_nic_file ();
|
||||
|
||||
// For emacs:
|
||||
// Local variables:
|
||||
// c-basic-offset: 4
|
||||
// c-indent-level: 4
|
||||
// tab-width: 4
|
||||
// End:
|
||||
|
||||
?>
|
||||
2
src/.gitignore
vendored
2
src/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
.toolcheck
|
||||
.echocheck
|
||||
TAGS*
|
||||
bin*
|
||||
bin-*
|
||||
|
||||
@ -77,6 +77,7 @@ SRCDIRS += drivers/net/efi
|
||||
SRCDIRS += drivers/net/tg3
|
||||
SRCDIRS += drivers/net/bnxt
|
||||
SRCDIRS += drivers/net/sfc
|
||||
SRCDIRS += drivers/net/marvell
|
||||
SRCDIRS += drivers/block
|
||||
SRCDIRS += drivers/nvs
|
||||
SRCDIRS += drivers/bitbash
|
||||
|
||||
@ -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
|
||||
#
|
||||
|
||||
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 */
|
||||
@ -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"
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -2,8 +2,8 @@ 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,4 +1,5 @@
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code32
|
||||
.arch i386
|
||||
|
||||
.section ".data", "aw", @progbits
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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
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 */
|
||||
@ -46,8 +46,12 @@ static void efiloong64_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__ ( "idle 0" );
|
||||
if ( ! efi_shutdown_in_progress )
|
||||
__asm__ __volatile__ ( "idle 0" );
|
||||
}
|
||||
|
||||
PROVIDE_NAP ( efiloong64, cpu_nap, efiloong64_cpu_nap );
|
||||
|
||||
@ -84,8 +84,8 @@ int cpuid_supported ( uint32_t function ) {
|
||||
return rc;
|
||||
|
||||
/* Find highest supported function number within this family */
|
||||
cpuid ( ( function & CPUID_EXTENDED ), 0, &max_function, &discard_b,
|
||||
&discard_c, &discard_d );
|
||||
cpuid ( ( function & ( CPUID_EXTENDED | CPUID_HYPERVISOR ) ), 0,
|
||||
&max_function, &discard_b, &discard_c, &discard_d );
|
||||
|
||||
/* Fail if maximum function number is meaningless (e.g. if we
|
||||
* are attempting to call an extended function on a CPU which
|
||||
|
||||
@ -38,7 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
* Bit 31 Extended function
|
||||
* Bits 30-24 (bit 22 = 1) Subfunction number
|
||||
* (bit 22 = 0) Number of consecutive functions to call, minus one
|
||||
* Bit 30 (bit 22 = 0) Hypervisor function
|
||||
* Bits 29-24 (bit 22 = 0) Number of consecutive functions to call, minus one
|
||||
* Bit 23 Return result as little-endian (used for strings)
|
||||
* Bit 22 Interpret bits 30-24 as a subfunction number
|
||||
* Bits 21-18 Unused
|
||||
@ -98,7 +99,7 @@ enum cpuid_flags {
|
||||
* @v tag Setting tag
|
||||
* @ret function Starting function number
|
||||
*/
|
||||
#define CPUID_FUNCTION( tag ) ( (tag) & 0x800000ffUL )
|
||||
#define CPUID_FUNCTION( tag ) ( (tag) & 0xc00000ffUL )
|
||||
|
||||
/**
|
||||
* Extract subfunction number from CPUID setting tag
|
||||
@ -108,6 +109,14 @@ enum cpuid_flags {
|
||||
*/
|
||||
#define CPUID_SUBFUNCTION( tag ) ( ( (tag) >> 24 ) & 0x7f )
|
||||
|
||||
/**
|
||||
* Extract number of consecutive functions from CPUID setting tag
|
||||
*
|
||||
* @v tag Setting tag
|
||||
* @ret num_functions Number of consecutive functions
|
||||
*/
|
||||
#define CPUID_NUM_FUNCTIONS( tag ) ( ( ( (tag) >> 24 ) & 0x3f ) + 1 )
|
||||
|
||||
/**
|
||||
* Extract register array from CPUID setting tag
|
||||
*
|
||||
@ -165,12 +174,13 @@ static int cpuid_settings_fetch ( struct settings *settings,
|
||||
|
||||
/* Call each function in turn */
|
||||
function = CPUID_FUNCTION ( setting->tag );
|
||||
subfunction = CPUID_SUBFUNCTION ( setting->tag );
|
||||
if ( setting->tag & CPUID_USE_SUBFUNCTION ) {
|
||||
function &= ~CPUID_HYPERVISOR;
|
||||
subfunction = CPUID_SUBFUNCTION ( setting->tag );
|
||||
num_functions = 1;
|
||||
} else {
|
||||
num_functions = ( subfunction + 1 );
|
||||
subfunction = 0;
|
||||
num_functions = CPUID_NUM_FUNCTIONS ( setting->tag );
|
||||
}
|
||||
for ( ; num_functions-- ; function++ ) {
|
||||
|
||||
|
||||
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
|
||||
@ -23,9 +23,8 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Set/clear CF on the stack as appropriate, assumes stack is as it should
|
||||
|
||||
@ -45,6 +45,7 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) {
|
||||
PCIDIRECT_CONFIG_ADDRESS );
|
||||
}
|
||||
|
||||
PROVIDE_PCIAPI_INLINE ( direct, pci_can_probe );
|
||||
PROVIDE_PCIAPI_INLINE ( direct, pci_discover );
|
||||
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
|
||||
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.arch i386
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define STACK_SIZE 8192
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
@ -11,9 +11,8 @@ FILE_LICENCE ( GPL2_OR_LATER )
|
||||
#define PIC2_ICR 0xa0
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
.section ".text16", "ax", @progbits
|
||||
.globl undiisr
|
||||
|
||||
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 */
|
||||
@ -33,6 +33,9 @@ struct x86_features {
|
||||
/** CPUID extended function */
|
||||
#define CPUID_EXTENDED 0x80000000UL
|
||||
|
||||
/** CPUID hypervisor function */
|
||||
#define CPUID_HYPERVISOR 0x40000000UL
|
||||
|
||||
/** Get vendor ID and largest standard function */
|
||||
#define CPUID_VENDOR_ID 0x00000000UL
|
||||
|
||||
|
||||
@ -32,6 +32,16 @@ extern int pcibios_read ( struct pci_device *pci, uint32_t command,
|
||||
extern int pcibios_write ( struct pci_device *pci, uint32_t command,
|
||||
uint32_t value );
|
||||
|
||||
/**
|
||||
* Check if PCI bus probing is allowed
|
||||
*
|
||||
* @ret ok Bus probing is allowed
|
||||
*/
|
||||
static inline __always_inline int
|
||||
PCIAPI_INLINE ( pcbios, pci_can_probe ) ( void ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read byte from PCI configuration space via PCI BIOS
|
||||
*
|
||||
|
||||
@ -15,4 +15,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define PCIAPI_PREFIX_cloud __cloud_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check if PCI bus probing is allowed
|
||||
*
|
||||
* @ret ok Bus probing is allowed
|
||||
*/
|
||||
static inline __always_inline int
|
||||
PCIAPI_INLINE ( cloud, pci_can_probe ) ( void ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* _IPXE_PCICLOUD_H */
|
||||
|
||||
@ -25,6 +25,16 @@ struct pci_device;
|
||||
|
||||
extern void pcidirect_prepare ( struct pci_device *pci, int where );
|
||||
|
||||
/**
|
||||
* Check if PCI bus probing is allowed
|
||||
*
|
||||
* @ret ok Bus probing is allowed
|
||||
*/
|
||||
static inline __always_inline int
|
||||
PCIAPI_INLINE ( direct, pci_can_probe ) ( void ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find next PCI bus:dev.fn address range in system
|
||||
*
|
||||
|
||||
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 );
|
||||
|
||||
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 );
|
||||
|
||||
@ -24,9 +24,8 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.arch i386
|
||||
.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;
|
||||
}
|
||||
|
||||
|
||||
@ -120,6 +120,7 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){
|
||||
return ( status >> 8 );
|
||||
}
|
||||
|
||||
PROVIDE_PCIAPI_INLINE ( pcbios, pci_can_probe );
|
||||
PROVIDE_PCIAPI ( pcbios, pci_discover, pcibios_discover );
|
||||
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte );
|
||||
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
|
||||
|
||||
@ -148,6 +148,7 @@ static void * pcicloud_ioremap ( struct pci_device *pci,
|
||||
return pcicloud->pci_ioremap ( pci, bus_addr, len );
|
||||
}
|
||||
|
||||
PROVIDE_PCIAPI_INLINE ( cloud, pci_can_probe );
|
||||
PROVIDE_PCIAPI ( cloud, pci_discover, pcicloud_discover );
|
||||
PROVIDE_PCIAPI ( cloud, pci_read_config_byte, pcicloud_read_config_byte );
|
||||
PROVIDE_PCIAPI ( cloud, pci_read_config_word, pcicloud_read_config_word );
|
||||
@ -165,24 +166,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 )
|
||||
|
||||
@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.code16
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -6,10 +6,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define STACK_SIZE 0x2000
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
|
||||
/*
|
||||
* Find active partition
|
||||
|
||||
@ -26,10 +26,9 @@ FILE_LICENCE ( GPL2_ONLY )
|
||||
|
||||
.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:
|
||||
|
||||
|
||||
@ -37,10 +37,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#define PSP_CMDLINE_START 0x81
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.org 0
|
||||
.code16
|
||||
.section ".prefix", "awx", @progbits
|
||||
|
||||
signature:
|
||||
|
||||
@ -3,10 +3,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
#include <librm.h>
|
||||
|
||||
.section ".note.GNU-stack", "", @progbits
|
||||
.text
|
||||
.code16
|
||||
.arch i386
|
||||
.section ".prefix", "awx", @progbits
|
||||
.code16
|
||||
.org 0
|
||||
.globl _hd_start
|
||||
_hd_start:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user