diff --git a/ts-livepatch-install b/ts-livepatch-install
new file mode 100755
index 0000000..23c4c20
--- /dev/null
+++ b/ts-livepatch-install
@@ -0,0 +1,37 @@
+#!/usr/bin/perl -w
+# This is part of "osstest", an automated testing framework for Xen.
+# Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+use strict qw(vars);
+use DBI;
+use Osstest;
+use Osstest::TestSupport;
+
+tsreadconfig();
+
+our ($whhost) = @ARGV;
+$whhost ||= 'host';
+
+our $ho= selecthost($whhost);
+
+sub extract () {
+    my %distpath;
+    target_extract_jobdistpath($ho, "xen", "path_xenlptdist",
+            $r{"$ho->{Ident}_xenbuildjob"} // $r{"xenbuildjob"},
+             \%distpath);
+}
+
+extract();
diff --git a/ts-livepatch-run b/ts-livepatch-run
new file mode 100755
index 0000000..b315d78
--- /dev/null
+++ b/ts-livepatch-run
@@ -0,0 +1,168 @@
+#!/usr/bin/perl -w
+# This is part of "osstest", an automated testing framework for Xen.
+# Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+use strict qw(vars);
+use Osstest;
+use POSIX;
+use Osstest::TestSupport;
+
+tsreadconfig();
+
+my @livepatch_files = qw(xen_hello_world.livepatch xen_replace_world.livepatch
+                         xen_bye_world.livepatch xen_nop.livepatch);
+
+my $xen_extra_info;
+my $xen_minor_ver;
+
+sub populate_data {
+    my @lines = split('\n', $_);
+    foreach my $line (@lines) {
+        my ($key, $values) = split /:/, $line;
+        $values = join("", $values);
+        chomp($values);
+        if ($key =~ m/xen_extra/) {
+            $xen_extra_info = $values;
+        }
+        if ($key =~ m/xen_minor/) {
+            $xen_minor_ver = $values;
+        }
+    }
+    return 1 if $xen_extra_info && $xen_minor_ver;
+    return 0;
+}
+
+sub check_for_hello_world {
+    return m/xen_extra/ && m/Hello World/;
+}
+
+sub check_for_stock {
+    return m/xen_extra/ && m/$xen_extra_info/;
+}
+
+# The NOP test-cases makes xen_minor_ver do nothing. Which means its
+# output value should be nothing like before NOPing it.
+sub check_versions {
+    my @lines = split('\n', $_);
+    foreach my $line (@lines) {
+        my ($key, $values) = split /:/, $line;
+        $values = join("", $values);
+        chomp($values);
+        if ($key =~ m/xen_minor/) {
+            if ($values ne $xen_minor_ver ) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+my @livepatch_tests = (
+    # Whether we can actually execute it.
+    { C => "xen-livepatch list" },
+    # And we better have a clean slate..
+    { C => "xen-livepatch list", OutputCheck => sub { return !m/xen_/; } },
+    # Sets the default values
+    { C => "xl info", OutputCheck => \&populate_data },
+    # Sanity check that populate_data did its job.
+    { C => "xl info",
+      OutputCheck => \&check_for_stock },
+    # Let it rip!
+    { C => "xen-livepatch revert xen_hello_world", rc => 256 },
+    { C => "xen-livepatch load xen_hello_world.livepatch" },
+    { C => "xen-livepatch load xen_hello_world.livepatch", rc => 256 },
+    { C => "xen-livepatch list",
+      OutputCheck => sub { m/xen_hello_world/ } },
+    { C => "xl info",
+      OutputCheck => \&check_for_hello_world },
+    { C => "xen-livepatch revert xen_hello_world" },
+    { C => "xl info",
+      OutputCheck => \&check_for_stock },
+    { C => "xen-livepatch unload xen_hello_world" },
+    { C => "xen-livepatch unload xen_hello_world", rc => 256 },
+    { C => "xl info",
+      OutputCheck => \&check_for_stock },
+    { C => "xen-livepatch load xen_hello_world.livepatch" },
+    { C => "xl info",
+      OutputCheck => \&check_for_hello_world },
+    { C => "xen-livepatch load xen_bye_world.livepatch" },
+    { C => "xl info",
+      OutputCheck => sub { m/xen_extra/ && m/Bye World/ } },
+    { C => "xen-livepatch upload xen_replace xen_replace_world.livepatch" },
+    { C => "xen-livepatch replace xen_replace" },
+    { C => "xl info",
+      OutputCheck => sub { m/xen_extra/ && m/Hello Again Wo/ } },
+    { C => "xen-livepatch apply xen_hello_world", rc => 256 },
+    { C => "xen-livepatch apply xen_bye_world", rc => 256 },
+    { C => "xen-livepatch apply xen_replace" },
+    { C => "xen-livepatch revert xen_replace" },
+    { C => "xen-livepatch unload xen_replace" },
+    { C => "xen-livepatch unload xen_hello_world" },
+    { C => "xen-livepatch unload xen_bye_world" },
+    { C => "xen-livepatch list",
+      OutputCheck => sub { !m/xen_/ } },
+    { C => "xl info",
+      OutputCheck => \&check_for_stock },
+    { C => "xen-livepatch load xen_nop.livepatch" },
+    { C => "xen-livepatch revert xen_nop" },
+    { C => "xen-livepatch apply xen_nop" },
+    { C => "xl info",
+      OutputCheck => \&check_versions },
+    { C => "xen-livepatch unload xen_nop", rc => 256 },
+    { C => "xen-livepatch revert xen_nop" },
+    { C => "xen-livepatch unload xen_nop" },
+    );
+
+our $ho = selecthost('host');
+
+sub livepatch_test () {
+    logm "Have ".(scalar @livepatch_tests)." test-cases\n";
+    my $rc;
+    my $output;
+
+    foreach my $test (@livepatch_tests) {
+        # Default rc is zero.
+        my $expected_rc = defined($test->{rc}) ? $test->{rc} : 0;
+        my $cmd = "set -e;cd /usr/lib/debug;$test->{C}";
+        my ($rc, $output) = target_cmd_output_root_status($ho, $cmd);
+
+        if ( $rc != $expected_rc ) {
+            logm "FAILED (got $rc, expected: $expected_rc): \n";
+            die $rc;
+        }
+        if (defined($test->{OutputCheck})) {
+            $_ = $output;
+            $rc=$test->{OutputCheck}->();
+            if ($rc ne 1) {
+                die "FAILED! OutputCheck=$test->{OutputCheck}, input=$output\n";
+            }
+        }
+   }
+   return 0;
+}
+
+sub livepatch_check () {
+    foreach my $file (@livepatch_files) {
+        if (!target_file_exists($ho, "/usr/lib/debug/$$file")) {
+            die "$file is missing!\n";
+        }
+    }
+}
+
+livepatch_check();
+my $livepatch_result = livepatch_test();
+logm("Livepatch test returned $livepatch_result");
+exit $livepatch_result;
