Revision 595d153dd1022392083ac93a1550382cbee127e0 authored by Michael Ellerman on 26 May 2020, 06:18:08 UTC, committed by Michael Ellerman on 26 May 2020, 07:32:37 UTC
Commit 702f09805222 ("powerpc/64s/exception: Remove lite interrupt
return") changed the interrupt return path to not restore non-volatile
registers by default, and explicitly restore them in paths where it is
required.

But it missed that the facility unavailable exception can sometimes
modify user registers, ie. when it does emulation of move from DSCR.

This is seen as a failure of the dscr_sysfs_thread_test:
  test: dscr_sysfs_thread_test
  [cpu 0] User DSCR should be 1 but is 0
  failure: dscr_sysfs_thread_test

So restore non-volatile GPRs after facility unavailable exceptions.

Currently the hypervisor facility unavailable exception is also wired
up to call facility_unavailable_exception().

In practice we should never take a hypervisor facility unavailable
exception for the DSCR. On older bare metal systems we set HFSCR_DSCR
unconditionally in __init_HFSCR, or on newer systems it should be
enabled via the "data-stream-control-register" device tree CPU
feature.

Even if it's not, since commit f3c99f97a3cd ("KVM: PPC: Book3S HV:
Don't access HFSCR, LPIDR or LPCR when running nested"), the KVM code
has unconditionally set HFSCR_DSCR when running guests.

So we should only get a hypervisor facility unavailable for the DSCR
if skiboot has disabled the "data-stream-control-register" feature,
and we are somehow in guest context but not via KVM.

Given all that, it should be unnecessary to add a restore of
non-volatile GPRs after the hypervisor facility exception, because we
never expect to hit that path. But equally we may as well add the
restore, because we never expect to hit that path, and if we ever did,
at least we would correctly restore the registers to their post
emulation state.

In future we can split the non-HV and HV facility unavailable handling
so that there is no emulation in the HV handler, and then remove the
restore for the HV case.

Fixes: 702f09805222 ("powerpc/64s/exception: Remove lite interrupt return")
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200526061808.2472279-1-mpe@ellerman.id.au
1 parent 8659a0e
Raw File
parse-maintainers.pl
#!/usr/bin/perl -w
# SPDX-License-Identifier: GPL-2.0

use strict;
use Getopt::Long qw(:config no_auto_abbrev);

my $input_file = "MAINTAINERS";
my $output_file = "MAINTAINERS.new";
my $output_section = "SECTION.new";
my $help = 0;
my $order = 0;
my $P = $0;

if (!GetOptions(
		'input=s' => \$input_file,
		'output=s' => \$output_file,
		'section=s' => \$output_section,
		'order!' => \$order,
		'h|help|usage' => \$help,
	    )) {
    die "$P: invalid argument - use --help if necessary\n";
}

if ($help != 0) {
    usage();
    exit 0;
}

sub usage {
    print <<EOT;
usage: $P [options] <pattern matching regexes>

  --input => MAINTAINERS file to read (default: MAINTAINERS)
  --output => sorted MAINTAINERS file to write (default: MAINTAINERS.new)
  --section => new sorted MAINTAINERS file to write to (default: SECTION.new)
  --order => Use the preferred section content output ordering (default: 0)
    Preferred ordering of section output is:
      M:  Person acting as a maintainer
      R:  Person acting as a patch reviewer
      L:  Mailing list where patches should be sent
      S:  Maintenance status
      W:  URI for general information
      Q:  URI for patchwork tracking
      B:  URI for bug tracking/submission
      C:  URI for chat
      P:  URI or file for subsystem specific coding styles
      T:  SCM tree type and location
      F:  File and directory pattern
      X:  File and directory exclusion pattern
      N:  File glob
      K:  Keyword - patch content regex

If <pattern match regexes> exist, then the sections that match the
regexes are not written to the output file but are written to the
section file.

EOT
}

# sort comparison functions
sub by_category($$) {
    my ($a, $b) = @_;

    $a = uc $a;
    $b = uc $b;

    # This always sorts last
    $a =~ s/THE REST/ZZZZZZ/g;
    $b =~ s/THE REST/ZZZZZZ/g;

    return $a cmp $b;
}

sub by_pattern($$) {
    my ($a, $b) = @_;
    my $preferred_order = 'MRLSWQBCPTFXNK';

    my $a1 = uc(substr($a, 0, 1));
    my $b1 = uc(substr($b, 0, 1));

    my $a_index = index($preferred_order, $a1);
    my $b_index = index($preferred_order, $b1);

    $a_index = 1000 if ($a_index == -1);
    $b_index = 1000 if ($b_index == -1);

    if (($a1 =~ /^F$/ && $b1 =~ /^F$/) ||
	($a1 =~ /^X$/ && $b1 =~ /^X$/)) {
	return $a cmp $b;
    }

    if ($a_index < $b_index) {
	return -1;
    } elsif ($a_index == $b_index) {
	return 0;
    } else {
	return 1;
    }
}

sub trim {
    my $s = shift;
    $s =~ s/\s+$//;
    $s =~ s/^\s+//;
    return $s;
}

sub alpha_output {
    my ($hashref, $filename) = (@_);

    return if ! scalar(keys %$hashref);

    open(my $file, '>', "$filename") or die "$P: $filename: open failed - $!\n";
    my $separator;
    foreach my $key (sort by_category keys %$hashref) {
	if ($key eq " ") {
	    print $file $$hashref{$key};
	} else {
	    if (! defined $separator) {
		$separator = "\n";
	    } else {
		print $file $separator;
	    }
	    print $file $key . "\n";
	    if ($order) {
		foreach my $pattern (sort by_pattern split('\n', %$hashref{$key})) {
		    print $file ($pattern . "\n");
		}
	    } else {
		foreach my $pattern (split('\n', %$hashref{$key})) {
		    print $file ($pattern . "\n");
		}
	    }
	}
    }
    close($file);
}

sub file_input {
    my ($hashref, $filename) = (@_);

    my $lastline = "";
    my $case = " ";
    $$hashref{$case} = "";

    open(my $file, '<', "$filename") or die "$P: $filename: open failed - $!\n";

    while (<$file>) {
        my $line = $_;

        # Pattern line?
        if ($line =~ m/^([A-Z]):\s*(.*)/) {
            $line = $1 . ":\t" . trim($2) . "\n";
            if ($lastline eq "") {
                $$hashref{$case} = $$hashref{$case} . $line;
                next;
            }
            $case = trim($lastline);
            exists $$hashref{$case} and die "Header '$case' already exists";
            $$hashref{$case} = $line;
            $lastline = "";
            next;
        }

        if ($case eq " ") {
            $$hashref{$case} = $$hashref{$case} . $lastline;
            $lastline = $line;
            next;
        }
        trim($lastline) eq "" or die ("Odd non-pattern line '$lastline' for '$case'");
        $lastline = $line;
    }
    $$hashref{$case} = $$hashref{$case} . $lastline;
    close($file);
}

my %hash;
my %new_hash;

file_input(\%hash, $input_file);

foreach my $type (@ARGV) {
    foreach my $key (keys %hash) {
	if ($key =~ /$type/ || $hash{$key} =~ /$type/) {
	    $new_hash{$key} = $hash{$key};
	    delete $hash{$key};
	}
    }
}

alpha_output(\%hash, $output_file);
alpha_output(\%new_hash, $output_section);

exit(0);
back to top