Compare commits

..

4 Commits

Author SHA1 Message Date
f4a0c7a752 WIP - refactoring done 2023-05-23 14:46:48 +01:00
ac991791cf WIP - refactored 2023-05-23 14:24:41 +01:00
4ade751029 WIP - tidying 2023-05-23 13:47:44 +01:00
cf79f3514c WIP - first successful sbat hack 2023-05-23 13:47:42 +01:00
435 changed files with 7041 additions and 32339 deletions

View File

@ -12,7 +12,7 @@ jobs:
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache@v4
uses: actions/cache@v3
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@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache permissions
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache/restore@v4
uses: actions/cache/restore@v3
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@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache permissions
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache/restore@v4
uses: actions/cache/restore@v3
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@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache permissions
run: |
sudo chown $(id -un) /var/cache/apt/archives
- name: Cache packages
uses: actions/cache/restore@v4
uses: actions/cache/restore@v3
with:
path: /var/cache/apt/archives/*.deb
key: apt-cache-${{ github.run_id }}-${{ github.run_attempt }}

View File

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Download Coverity Scan
run: |
curl --form token=${{ secrets.COVERITY_SCAN_TOKEN }} \

View File

@ -46,19 +46,11 @@ def create_snapshot(region, description, image):
return snapshot_id
def import_image(region, name, architecture, image, public, overwrite):
def import_image(region, name, architecture, image, public):
"""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])
@ -96,8 +88,6 @@ 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',
@ -125,8 +115,7 @@ with ThreadPoolExecutor(max_workers=len(imports)) as executor:
name=args.name,
architecture=architectures[image],
image=image,
public=args.public,
overwrite=args.overwrite): (region, image)
public=args.public): (region, image)
for region, image in imports}
results = {futures[future]: future.result()
for future in as_completed(futures)}

View File

@ -1,68 +0,0 @@
#!/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)

View File

@ -1,167 +0,0 @@
#!/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))

View File

@ -1,146 +0,0 @@
#!/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)

View File

@ -1,80 +0,0 @@
#!/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)

View File

@ -0,0 +1,62 @@
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

View File

@ -0,0 +1,62 @@
<?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>

View File

@ -0,0 +1,311 @@
<?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:
?>

View File

@ -0,0 +1,69 @@
<?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:
?>

View File

@ -0,0 +1,63 @@
<?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 &mdash; 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 ); ?>
&nbsp;&nbsp;
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>

View File

@ -0,0 +1 @@
Automatic booting

View File

@ -0,0 +1 @@
Tenths of a second for which the shell banner should appear

View File

@ -0,0 +1,3 @@
Serial Console I/O port address. Common addresses are:<br>
COM1 => 0x3f8, COM2 => 0x2f8, COM3 => 0x3e8, COM4 => 0x2e8

View File

@ -0,0 +1 @@
Serial Console Data bits

View File

@ -0,0 +1 @@
Serial Console Parity: 0=None, 1=Odd, 2=Even

View File

@ -0,0 +1 @@
Keep settings from a previous user of the serial port

View File

@ -0,0 +1 @@
Serial Console Baud rate

View File

@ -0,0 +1 @@
Serial Console Stop bits

View File

@ -0,0 +1 @@
Option configuration console

View File

@ -0,0 +1 @@
Enable Default BIOS console

View File

@ -0,0 +1 @@
Enable Serial port console

View File

@ -0,0 +1 @@
Wireless WEP encryption support

View File

@ -0,0 +1 @@
Wireless WPA encryption support

View File

@ -0,0 +1 @@
Wireless WPA2 encryption support

View File

@ -0,0 +1 @@
DHCP management commands

View File

@ -0,0 +1 @@
DNS resolver

View File

@ -0,0 +1 @@
File Transfer Protocol

View File

@ -0,0 +1 @@
Hypertext Transfer Protocol

View File

@ -0,0 +1 @@
Trivial File Transfer Protocol

View File

@ -0,0 +1 @@
Interface management commands

View File

@ -0,0 +1 @@
Linux bzImage image support

View File

@ -0,0 +1 @@
Image management commands

View File

@ -0,0 +1 @@
ELF image support

View File

@ -0,0 +1 @@
MultiBoot image support

View File

@ -0,0 +1 @@
NBI image support

View File

@ -0,0 +1 @@
PXE image support

View File

@ -0,0 +1 @@
iPXE script image support

View File

@ -0,0 +1 @@
Wireless interface management commands

View File

@ -0,0 +1 @@
NMB resolver

View File

@ -0,0 +1 @@
Non-volatile option storage commands

View File

@ -0,0 +1 @@
Routing table management commands

View File

@ -0,0 +1 @@
SAN boot commands

View File

@ -0,0 +1,531 @@
<?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:
?>

View File

@ -0,0 +1,51 @@
<?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:
?>

View File

@ -0,0 +1,47 @@
<?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 ?>

View File

@ -1,5 +1,10 @@
/*
* Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<?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
@ -13,25 +18,24 @@
*
* 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.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
?>
/**
* @file
*
* Null multiprocessor API
*
*/
#include <ipxe/mp.h>
PROVIDE_MPAPI_INLINE ( null, mp_address );
PROVIDE_MPAPI_INLINE ( null, mp_exec_boot );
PROVIDE_MPAPI_INLINE ( null, mp_start_all );
<html>
<head>
<link rev="made" href="mailto:<?php echo "${webmaster_email}" ?>">
<meta name="keywords" content="rom, etherboot, ipxe, open source, rom-o-matic.net">
<title><?php echo $header_title ?></title>
<meta name="description" content="<?php echo $description ?>">
</head>
<h1>
<?php echo "$html_title" ?>&nbsp;
</h1>
<hr>
<h2>
<?php echo "$html_tagline" ?>
</h2>
</form>
<hr>

View File

@ -0,0 +1,684 @@
<?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>&nbsp;</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>&nbsp;</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 ( "&nbsp;&nbsp;&nbsp;" . $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
View File

@ -1,4 +1,4 @@
.toolcheck
.echocheck
TAGS*
bin-*
bin*

View File

@ -77,7 +77,6 @@ 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

View File

@ -23,9 +23,9 @@ NON_AUTO_MEDIA += efidrv
NON_AUTO_MEDIA += drv.efi
NON_AUTO_MEDIA += efirom
# Include SNP and MNP drivers in the all-drivers build
# Include SNP driver in the all-drivers build
#
DRIVERS_net += snp mnp
DRIVERS_net += snp
# Rules for building EFI files
#
@ -50,10 +50,6 @@ $(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
$(QM)$(ECHO) " [CAB] $@"
$(Q)$(LCAB) -n -q $(ALL_drv.efi) $@
$(BIN)/%.iso : $(BIN)/%.efi util/genfsimg
$(QM)$(ECHO) " [GENFSIMG] $@"
$(Q)util/genfsimg -o $@ $<
$(BIN)/%.usb : $(BIN)/%.efi util/genfsimg
$(BIN)/%.iso $(BIN)/%.usb : $(BIN)/%.efi util/genfsimg
$(QM)$(ECHO) " [GENFSIMG] $@"
$(Q)util/genfsimg -o $@ $<

View File

@ -502,13 +502,6 @@ LDFLAGS += --gc-sections
#
LDFLAGS += -static
# Use separate code segment if supported by linker
#
ZSC_TEST = $(LD) -z separate-code --version 2>&1 > /dev/null
ZSC_FLAGS := $(shell [ -z "`$(ZSC_TEST)`" ] && \
$(ECHO) '-z separate-code -z max-page-size=4096')
LDFLAGS += $(ZSC_FLAGS)
# compiler.h is needed for our linking and debugging system
#
CFLAGS += -include include/compiler.h
@ -1009,7 +1002,6 @@ endif
# Device ID tables (using IDs from ROM definition file)
#
define obj_pci_id_asm
.section ".note.GNU-stack", "", $(ASM_TCHAR)progbits
.section ".pci_devlist.$(1)", "a", $(ASM_TCHAR)progbits
.globl pci_devlist_$(1)
pci_devlist_$(1):
@ -1179,7 +1171,7 @@ BLIB = $(BIN)/blib.a
$(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
$(Q)$(RM) $(BLIB)
$(QM)$(ECHO) " [AR] $@"
$(Q)$(AR) rcD $@ $(sort $(BLIB_OBJS))
$(Q)$(AR) rD $@ $(sort $(BLIB_OBJS))
$(Q)$(OBJCOPY) --enable-deterministic-archives \
--prefix-symbols=$(SYMBOL_PREFIX) $@
$(Q)$(RANLIB) -D $@

View File

@ -9,5 +9,4 @@ INCDIRS += arch/arm/include
# ARM-specific directories containing source files
#
SRCDIRS += arch/arm/core
SRCDIRS += arch/arm/interface/efi

View File

@ -46,7 +46,7 @@ union arm32_io_qword {
*
* This is not atomic for ARM32.
*/
static __unused uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
static uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
volatile union arm32_io_qword *ptr =
container_of ( io_addr, union arm32_io_qword, qword );
union arm32_io_qword tmp;
@ -64,8 +64,7 @@ static __unused uint64_t arm32_readq ( volatile uint64_t *io_addr ) {
*
* This is not atomic for ARM32.
*/
static __unused void arm32_writeq ( uint64_t data,
volatile uint64_t *io_addr ) {
static void arm32_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
volatile union arm32_io_qword *ptr =
container_of ( io_addr, union arm32_io_qword, qword );
union arm32_io_qword tmp;
@ -83,6 +82,7 @@ PROVIDE_IOAPI_INLINE ( arm, readl );
PROVIDE_IOAPI_INLINE ( arm, writeb );
PROVIDE_IOAPI_INLINE ( arm, writew );
PROVIDE_IOAPI_INLINE ( arm, writel );
PROVIDE_IOAPI_INLINE ( arm, iodelay );
PROVIDE_IOAPI_INLINE ( arm, mb );
#ifdef __aarch64__
PROVIDE_IOAPI_INLINE ( arm, readq );
@ -91,4 +91,3 @@ PROVIDE_IOAPI_INLINE ( arm, writeq );
PROVIDE_IOAPI ( arm, readq, arm32_readq );
PROVIDE_IOAPI ( arm, writeq, arm32_writeq );
#endif
PROVIDE_DUMMY_PIO ( arm );

View File

@ -1,12 +0,0 @@
#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 */

View File

@ -9,4 +9,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/io.h>
#endif /* _BITS_PCI_IO_H */

View File

@ -15,8 +15,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define IOAPI_PREFIX_arm __arm_
#endif
#include <ipxe/dummy_pio.h>
/*
* Memory space mappings
*
@ -79,6 +77,55 @@ ARM_WRITEX ( w, uint16_t, "h", "" );
ARM_WRITEX ( l, uint32_t, "", "" );
#endif
/*
* Dummy PIO reads and writes up to 32 bits
*
* There is no common standard for I/O-space access for ARM, and
* non-MMIO peripherals are vanishingly rare. Provide dummy
* implementations that will allow code to link and should cause
* drivers to simply fail to detect hardware at runtime.
*
*/
#define ARM_INX( _suffix, _type ) \
static inline __always_inline _type \
IOAPI_INLINE ( arm, in ## _suffix ) ( volatile _type *io_addr __unused) { \
return ~( (_type) 0 ); \
} \
static inline __always_inline void \
IOAPI_INLINE ( arm, ins ## _suffix ) ( volatile _type *io_addr __unused, \
_type *data, unsigned int count ) { \
memset ( data, 0xff, count * sizeof ( *data ) ); \
}
ARM_INX ( b, uint8_t );
ARM_INX ( w, uint16_t );
ARM_INX ( l, uint32_t );
#define ARM_OUTX( _suffix, _type ) \
static inline __always_inline void \
IOAPI_INLINE ( arm, out ## _suffix ) ( _type data __unused, \
volatile _type *io_addr __unused ) { \
/* Do nothing */ \
} \
static inline __always_inline void \
IOAPI_INLINE ( arm, outs ## _suffix ) ( volatile _type *io_addr __unused, \
const _type *data __unused, \
unsigned int count __unused ) { \
/* Do nothing */ \
}
ARM_OUTX ( b, uint8_t );
ARM_OUTX ( w, uint16_t );
ARM_OUTX ( l, uint32_t );
/*
* Slow down I/O
*
*/
static inline __always_inline void
IOAPI_INLINE ( arm, iodelay ) ( void ) {
/* Nothing to do */
}
/*
* Memory barrier
*
@ -93,7 +140,4 @@ IOAPI_INLINE ( arm, mb ) ( void ) {
#endif
}
/* Dummy PIO */
DUMMY_PIO ( arm );
#endif /* _IPXE_ARM_IO_H */

View File

@ -46,12 +46,8 @@ 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().
*/
if ( ! efi_shutdown_in_progress )
__asm__ __volatile__ ( "wfi" );
__asm__ __volatile__ ( "wfi" );
}
PROVIDE_NAP ( efiarm, cpu_nap, efiarm_cpu_nap );

View File

@ -36,23 +36,19 @@ 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,
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 );
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 i;
unsigned int j;
uint32_t multiplicand_element;
@ -66,9 +62,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 < multiplicand_size ; i++ ) {
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < multiplier_size ; j++ ) {
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
@ -77,7 +73,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t"
"ldr %3, [%0]\n\t"

View File

@ -310,9 +310,7 @@ 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,
unsigned int multiplier_size,
uint32_t *value0 );
uint32_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */

View File

@ -1,6 +1,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", %progbits
.text
.thumb
/**

View File

@ -1,6 +1,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", %progbits
.text
.arm
/**

View File

@ -36,23 +36,19 @@ 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,
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 );
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 i;
unsigned int j;
uint64_t multiplicand_element;
@ -67,9 +63,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 < multiplicand_size ; i++ ) {
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < multiplier_size ; j++ ) {
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
@ -78,7 +74,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "mul %1, %6, %7\n\t"
"umulh %2, %6, %7\n\t"

View File

@ -1,6 +1,5 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", %progbits
.text
/* Must match jmp_buf structure layout */

View File

@ -311,9 +311,7 @@ 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,
unsigned int multiplier_size,
uint64_t *value0 );
uint64_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */

View File

@ -9,7 +9,6 @@
* Interrupt handlers
****************************************************************************
*/
.section ".note.GNU-stack", "", @progbits
.section ".text", "ax", @progbits
.code32

View File

@ -1,9 +1,8 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", @progbits
.text
.code32
.arch i386
.code32
/* Must match jmp_buf structure layout */
.struct 0

View File

@ -1,5 +1,3 @@
.section ".note.GNU-stack", "", @progbits
.code32
.arch i386
.section ".data", "aw", @progbits

View File

@ -20,7 +20,6 @@ CFLAGS += -fshort-wchar
# LoongArch64-specific directories containing source files
SRCDIRS += arch/loong64/core
SRCDIRS += arch/loong64/interface/efi
# Include platform-specific Makefile
MAKEDEPS += arch/loong64/Makefile.$(PLATFORM)

View File

@ -1,14 +0,0 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Specify EFI image builder
#
ELF2EFI = $(ELF2EFI64)
# Specify EFI boot file
#
EFI_BOOT_FILE = bootloongarch64.efi
# Include generic EFI Makefile
#
MAKEDEPS += Makefile.efi
include Makefile.efi

View File

@ -37,23 +37,19 @@ 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,
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 );
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 i;
unsigned int j;
uint64_t multiplicand_element;
@ -68,9 +64,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 < multiplicand_size ; i++ ) {
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < multiplier_size ; j++ ) {
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
@ -79,7 +75,7 @@ void bigint_multiply_raw ( const uint64_t *multiplicand0,
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "mul.d %1, %6, %7\n\t"
"mulh.du %2, %6, %7\n\t"

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/io.h>
#include <ipxe/loong64_io.h>
/** @file
*
* iPXE I/O API for LoongArch64
*
*/
PROVIDE_IOAPI_INLINE ( loong64, phys_to_bus );
PROVIDE_IOAPI_INLINE ( loong64, bus_to_phys );
PROVIDE_IOAPI_INLINE ( loong64, readb );
PROVIDE_IOAPI_INLINE ( loong64, readw );
PROVIDE_IOAPI_INLINE ( loong64, readl );
PROVIDE_IOAPI_INLINE ( loong64, readq );
PROVIDE_IOAPI_INLINE ( loong64, writeb );
PROVIDE_IOAPI_INLINE ( loong64, writew );
PROVIDE_IOAPI_INLINE ( loong64, writel );
PROVIDE_IOAPI_INLINE ( loong64, writeq );
PROVIDE_IOAPI_INLINE ( loong64, mb );
PROVIDE_DUMMY_PIO ( loong64 );

View File

@ -53,37 +53,34 @@ 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__ ( "\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 */
__asm__ __volatile__ ( "move $t0, $zero\n"
"1:\n\t"
"ld.d %3, %0, 0\n\t"
"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\n\t"
"bnez %2, 1b"
: "=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 ), "5" ( 0 ) );
: "0" ( addend0 ),
"1" ( value0 ),
"2" ( size )
: "t0", "t1" );
}
/**
@ -96,43 +93,35 @@ 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;
__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 ) );
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);
}
/**
@ -143,37 +132,30 @@ 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;
__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" );
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 );
}
/**
@ -184,37 +166,27 @@ 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_carry;
uint64_t discard_temp;
uint64_t discard_value_j;
unsigned int discard_size;
__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" );
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 );
}
/**
@ -358,9 +330,7 @@ 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,
unsigned int multiplier_size,
uint64_t *value0 );
uint64_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */

View File

@ -12,6 +12,4 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Page shift */
#define PAGE_SHIFT 12
#include <ipxe/loong64_io.h>
#endif /* _BITS_IO_H */

View File

@ -1,12 +0,0 @@
#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 */

View File

@ -9,6 +9,4 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efiloong64_nap.h>
#endif /* _BITS_NAP_H */
#endif /* _BITS_MAP_H */

View File

@ -1,18 +0,0 @@
#ifndef _IPXE_EFILOONG64_NAP_H
#define _IPXE_EFILOONG64_NAP_H
/** @file
*
* EFI CPU sleeping
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef NAP_EFILOONG64
#define NAP_PREFIX_efiloong64
#else
#define NAP_PREFIX_efiloong64 __efiloong64_
#endif
#endif /* _IPXE_EFILOONG64_NAP_H */

View File

@ -1,82 +0,0 @@
#ifndef _IPXE_LOONG64_IO_H
#define _IPXE_LOONG64_IO_H
/** @file
*
* iPXE I/O API for LoongArch64
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef IOAPI_LOONG64
#define IOAPI_PREFIX_loong64
#else
#define IOAPI_PREFIX_loong64 __loong64_
#endif
#include <ipxe/dummy_pio.h>
/*
* Memory space mappings
*
*/
/*
* Physical<->Bus address mappings
*
*/
static inline __always_inline unsigned long
IOAPI_INLINE ( loong64, phys_to_bus ) ( unsigned long phys_addr ) {
return phys_addr;
}
static inline __always_inline unsigned long
IOAPI_INLINE ( loong64, bus_to_phys ) ( unsigned long bus_addr ) {
return bus_addr;
}
/*
* MMIO reads and writes up to native word size
*
*/
#define LOONG64_READX( _suffix, _type, _insn_suffix ) \
static inline __always_inline _type \
IOAPI_INLINE ( loong64, read ## _suffix ) ( volatile _type *io_addr ) { \
_type data; \
__asm__ __volatile__ ( "ld." _insn_suffix " %0, %1" \
: "=r" ( data ) : "m" ( *io_addr ) ); \
return data; \
}
LOONG64_READX ( b, uint8_t, "bu");
LOONG64_READX ( w, uint16_t, "hu");
LOONG64_READX ( l, uint32_t, "wu");
LOONG64_READX ( q, uint64_t, "d");
#define LOONG64_WRITEX( _suffix, _type, _insn_suffix ) \
static inline __always_inline void \
IOAPI_INLINE ( loong64, write ## _suffix ) ( _type data, \
volatile _type *io_addr ) { \
__asm__ __volatile__ ( "st." _insn_suffix " %0, %1" \
: : "r" ( data ), "m" ( *io_addr ) ); \
}
LOONG64_WRITEX ( b, uint8_t, "b");
LOONG64_WRITEX ( w, uint16_t, "h");
LOONG64_WRITEX ( l, uint32_t, "w" );
LOONG64_WRITEX ( q, uint64_t, "d");
/*
* Memory barrier
*
*/
static inline __always_inline void
IOAPI_INLINE ( loong64, mb ) ( void ) {
__asm__ __volatile__ ( "dbar 0" );
}
/* Dummy PIO */
DUMMY_PIO ( loong64 );
#endif /* _IPXE_LOONG64_IO_H */

View File

@ -1,57 +0,0 @@
/*
* Copyright (c) 2023, Xiaotian Wu <wuxiaotian@loongson.cn>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/nap.h>
#include <ipxe/efi/efi.h>
/** @file
*
* iPXE CPU sleeping API for EFI
*
*/
/**
* Sleep until next interrupt
*
*/
static void efiloong64_cpu_nap ( void ) {
/*
* I can't find any EFI API that allows us to put the CPU to
* sleep. The CpuSleep() function is defined in CpuLib.h, but
* isn't part of any exposed protocol so we have no way to
* call it.
*
* The EFI shell doesn't seem to bother sleeping the CPU; it
* just sits there idly burning power.
*
* If a shutdown is in progess, there may be nothing to
* generate an interrupt since the timer is disabled in the
* first step of ExitBootServices().
*/
if ( ! efi_shutdown_in_progress )
__asm__ __volatile__ ( "idle 0" );
}
PROVIDE_NAP ( efiloong64, cpu_nap, efiloong64_cpu_nap );

View File

@ -13,13 +13,6 @@ LDSCRIPT_PREFIX = arch/x86/scripts/prefixonly.lds
#
LDFLAGS += -N --no-check-sections
# Do not warn about RWX segments (required by most prefixes)
#
WRWX_TEST = $(LD) --warn-rwx-segments --version 2>&1 > /dev/null
WRWX_FLAGS := $(shell [ -z "`$(WRWX_TEST)`" ] && \
$(ECHO) '--no-warn-rwx-segments')
LDFLAGS += $(WRWX_FLAGS)
# Media types.
#
MEDIA += rom
@ -61,15 +54,9 @@ LIST_NAME_mrom := ROMS
LIST_NAME_pcirom := ROMS
LIST_NAME_isarom := ROMS
# ISO images
# ISO or FAT filesystem images
NON_AUTO_MEDIA += iso
$(BIN)/%.iso : $(BIN)/%.lkrn util/genfsimg
$(QM)$(ECHO) " [GENFSIMG] $@"
$(Q)util/genfsimg -o $@ $<
# FAT filesystem images (via syslinux)
NON_AUTO_MEDIA += sdsk
$(BIN)/%.sdsk : $(BIN)/%.lkrn util/genfsimg
$(BIN)/%.iso $(BIN)/%.sdsk: $(BIN)/%.lkrn util/genfsimg
$(QM)$(ECHO) " [GENFSIMG] $@"
$(Q)util/genfsimg -o $@ $<

View File

@ -84,8 +84,8 @@ int cpuid_supported ( uint32_t function ) {
return rc;
/* Find highest supported function number within this family */
cpuid ( ( function & ( CPUID_EXTENDED | CPUID_HYPERVISOR ) ), 0,
&max_function, &discard_b, &discard_c, &discard_d );
cpuid ( ( function & CPUID_EXTENDED ), 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

View File

@ -38,8 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* Bit 31 Extended function
* Bits 30-24 (bit 22 = 1) Subfunction number
* Bit 30 (bit 22 = 0) Hypervisor function
* Bits 29-24 (bit 22 = 0) Number of consecutive functions to call, minus one
* (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
@ -99,7 +98,7 @@ enum cpuid_flags {
* @v tag Setting tag
* @ret function Starting function number
*/
#define CPUID_FUNCTION( tag ) ( (tag) & 0xc00000ffUL )
#define CPUID_FUNCTION( tag ) ( (tag) & 0x800000ffUL )
/**
* Extract subfunction number from CPUID setting tag
@ -109,14 +108,6 @@ 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
*
@ -174,13 +165,12 @@ 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++ ) {

View File

@ -1,197 +0,0 @@
/*
* 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

View File

@ -22,9 +22,9 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", @progbits
.code16
.text
.arch i386
.code16
/****************************************************************************
* Set/clear CF on the stack as appropriate, assumes stack is as it should

View File

@ -45,7 +45,6 @@ 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 );

View File

@ -1,6 +1,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", @progbits
.arch i386
#ifdef __x86_64__
#define STACK_SIZE 8192

View File

@ -1,6 +1,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", @progbits
.arch i386
/****************************************************************************
* Internal stack

View File

@ -1,257 +0,0 @@
/*
* 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

View File

@ -36,23 +36,19 @@ 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,
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 );
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 i;
unsigned int j;
uint32_t multiplicand_element;
@ -66,9 +62,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 < multiplicand_size ; i++ ) {
for ( i = 0 ; i < size ; i++ ) {
multiplicand_element = multiplicand->element[i];
for ( j = 0 ; j < multiplier_size ; j++ ) {
for ( j = 0 ; j < size ; j++ ) {
multiplier_element = multiplier->element[j];
result_elements = &result->element[ i + j ];
/* Perform a single multiply, and add the
@ -77,7 +73,7 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
* never overflow beyond the end of the
* result, since:
*
* a < 2^{n}, b < 2^{m} => ab < 2^{n+m}
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
*/
__asm__ __volatile__ ( "mull %5\n\t"
"addl %%eax, (%6,%2,4)\n\t"

View File

@ -10,9 +10,9 @@ FILE_LICENCE ( GPL2_OR_LATER )
#define PIC1_ICR 0x20
#define PIC2_ICR 0xa0
.section ".note.GNU-stack", "", @progbits
.code16
.text
.arch i386
.code16
.section ".text16", "ax", @progbits
.globl undiisr

View File

@ -1,798 +0,0 @@
/*
* 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,
};

View File

@ -323,9 +323,7 @@ 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,
unsigned int multiplier_size,
uint32_t *value0 );
uint32_t *value0, unsigned int size );
#endif /* _BITS_BIGINT_H */

View File

@ -44,7 +44,6 @@ 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 )

View File

@ -1,14 +0,0 @@
#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 */

View File

@ -1,32 +0,0 @@
#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 */

View File

@ -33,9 +33,6 @@ 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

View File

@ -32,16 +32,6 @@ 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
*

View File

@ -15,14 +15,4 @@ 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 */

View File

@ -25,16 +25,6 @@ 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
*

Some files were not shown because too many files have changed in this diff Show More