Skip to content

Commit ecfd482

Browse files
author
Alex
committed
Add S3 sleep support for Linux
The new command is --prepareForS3Sleep, and it should be called every new boot, as it stores the drive key (password hash) in kernel memory.
1 parent 69a2a4d commit ecfd482

12 files changed

+130
-4
lines changed

Common/DtaDev.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,9 @@ void DtaDev::puke()
319319
if (disk_info.Unknown)
320320
cout << "**** " << (uint16_t)disk_info.Unknown << " **** Unknown function codes IGNORED " << std::endl;
321321
}
322+
323+
uint8_t DtaDev::prepareForS3Sleep(uint8_t lockingrange, char* password)
324+
{
325+
LOG(E) << "S3 sleep not supported on this platform";
326+
return 1;
327+
}

Common/DtaDev.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,11 @@ class DtaDev {
252252
* @param password Password of administrative authority for locking range
253253
*/
254254
virtual uint8_t eraseLockingRange(uint8_t lockingrange, char * password) = 0;
255+
/** Optionally implemented s3 sleep support.
256+
* On Linux, it saves the password to the kernel to use on resume.
257+
* @param password the password to save to the kernel
258+
*/
259+
virtual uint8_t prepareForS3Sleep(uint8_t lockingrange, char* password);
255260
/** Dumps an object for diagnostic purposes
256261
* @param sp index into the OPALUID table for the SP the object is in
257262
* @param auth the authority ti use for the dump

Common/DtaOptions.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ void usage()
9999
printf("--printPasswordHash <password> <device>\n");
100100
printf(" print the hash of the password \n");
101101
printf(" as computed by sedutil. Hex-ecoded.\n");
102+
printf("--prepareForS3Sleep <0...n> <Admin1password> <device>\n");
103+
printf(" Automatically unlock range after S3 resume\n");
104+
printf(" This command will save the password to kernel memory\n");
102105
printf("\n");
103106
printf("Examples \n");
104107
printf("sedutil-cli --scan \n");
@@ -522,6 +525,27 @@ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts)
522525
OPTION_IS(password)
523526
OPTION_IS(device)
524527
END_OPTION
528+
BEGIN_OPTION(prepareForS3Sleep, 3)
529+
TESTARG(0, lockingrange, 0)
530+
TESTARG(1, lockingrange, 1)
531+
TESTARG(2, lockingrange, 2)
532+
TESTARG(3, lockingrange, 3)
533+
TESTARG(4, lockingrange, 4)
534+
TESTARG(5, lockingrange, 5)
535+
TESTARG(6, lockingrange, 6)
536+
TESTARG(7, lockingrange, 7)
537+
TESTARG(8, lockingrange, 8)
538+
TESTARG(9, lockingrange, 9)
539+
TESTARG(10, lockingrange, 10)
540+
TESTARG(11, lockingrange, 11)
541+
TESTARG(12, lockingrange, 12)
542+
TESTARG(13, lockingrange, 13)
543+
TESTARG(14, lockingrange, 14)
544+
TESTARG(15, lockingrange, 15)
545+
TESTFAIL("Invalid Locking Range (0-15)")
546+
OPTION_IS(password)
547+
OPTION_IS(device)
548+
END_OPTION
525549
BEGIN_OPTION(rawCmd, 7) i += 6; OPTION_IS(device) END_OPTION
526550
else {
527551
LOG(E) << "Invalid command line argument " << argv[i];

Common/DtaOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ typedef enum _sedutiloption {
9797
objDump,
9898
printDefaultPassword,
9999
printPasswordHash,
100+
prepareForS3Sleep,
100101
rawCmd,
101102

102103
} sedutiloption;

Common/sedutil.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ int main(int argc, char * argv[])
265265
LOG(D) << "print password hash";
266266
return d->printPasswordHash(argv[opts.password]);
267267
break;
268+
case sedutiloption::prepareForS3Sleep:
269+
LOG(D) << "Preparing for S3 sleep " << (uint16_t) opts.lockingrange;
270+
return d->prepareForS3Sleep(opts.lockingrange, argv[opts.password]);
271+
break;
268272
case sedutiloption::rawCmd:
269273
LOG(D) << "Performing cmdDump ";
270274
return d->rawCmd(argv[argc - 7], argv[argc - 6], argv[argc - 5], argv[argc - 4], argv[argc - 3], argv[argc - 2]);

Makefile.am

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ sedutil_cli_SOURCES = linux/Version.h Common/sedutil.cpp Common/DtaOptions.cpp C
2525
linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxNvme.h \
2626
linux/DtaDevLinuxSata.cpp linux/DtaDevLinuxSata.h \
2727
linux/DtaDevOS.cpp linux/DtaDevOS.h \
28-
linux/DtaDevLinuxDrive.h linux/os.h \
28+
linux/DtaDevLinuxDrive.cpp linux/DtaDevLinuxDrive.h \
29+
linux/os.h \
2930
$(SEDUTIL_COMMON_CODE)
3031
CLEANFILES = linux/Version.h
3132
BUILT_SOURCES = linux/Version.h
@@ -36,7 +37,8 @@ linuxpba_SOURCES = LinuxPBA/LinuxPBA.cpp LinuxPBA/GetPassPhrase.cpp LinuxPBA/Unl
3637
linux/DtaDevLinuxNvme.cpp linux/DtaDevLinuxNvme.h \
3738
linux/DtaDevLinuxSata.cpp linux/DtaDevLinuxSata.h \
3839
linux/DtaDevOS.cpp linux/DtaDevOS.h \
39-
linux/DtaDevLinuxDrive.h linux/os.h \
40+
linux/DtaDevLinuxDrive.cpp linux/DtaDevLinuxDrive.h \
41+
linux/os.h \
4042
\
4143
$(SEDUTIL_COMMON_CODE)
4244
EXTRA_DIST = linux/GitVersion.sh linux/PSIDRevert_LINUX.txt linux/TestSuite.sh README.md docs/sedutil-cli.8

linux/DtaDevLinuxDrive.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* C:B**************************************************************************
2+
Copyright 2017, Alex Badics
3+
4+
This file is part of sedutil.
5+
6+
sedutil is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
sedutil is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with sedutil. If not, see <http://www.gnu.org/licenses/>.
18+
19+
* C:E********************************************************************** */
20+
#include "os.h"
21+
#include <sys/ioctl.h>
22+
#include <linux/sed-opal.h>
23+
#include "DtaDevLinuxDrive.h"
24+
25+
using namespace std;
26+
27+
uint8_t DtaDevLinuxDrive::prepareForS3Sleep(uint8_t lockingrange, const vector<uint8_t> &password_hash)
28+
{
29+
LOG(D1) << "Entering DtaDevLinuxDrive::prepareForS3Sleep";
30+
31+
opal_lock_unlock opal_ioctl_data={};
32+
opal_ioctl_data.l_state = OPAL_RW;
33+
opal_ioctl_data.session.who = OPAL_ADMIN1;
34+
opal_ioctl_data.session.opal_key.lr = 0;
35+
36+
size_t hash_len=min(password_hash.size(), sizeof(opal_ioctl_data.session.opal_key.key));
37+
LOG(D2) << "Setting a hash of length" << hash_len;
38+
39+
memcpy(opal_ioctl_data.session.opal_key.key, &password_hash[0], hash_len);
40+
opal_ioctl_data.session.opal_key.key_len = hash_len;
41+
42+
int err = ioctl(fd, IOC_OPAL_SAVE, &opal_ioctl_data);
43+
if (err < 0)
44+
return errno;
45+
return 0;
46+
}

linux/DtaDevLinuxDrive.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ along with sedutil. If not, see <http://www.gnu.org/licenses/>.
1818
1919
* C:E********************************************************************** */
2020
#pragma once
21+
#include <vector>
2122
#include "DtaStructures.h"
2223

24+
using namespace std;
2325
/** virtual implementation for a disk interface-generic disk drive
2426
*/
2527
class DtaDevLinuxDrive {
@@ -45,4 +47,7 @@ class DtaDevLinuxDrive {
4547
void * buffer, uint32_t bufferlen) = 0;
4648
/** Routine to send an identify to the device */
4749
virtual void identify(OPAL_DiskInfo& disk_info) = 0;
50+
/** Save the password hash to the kernel for S3 sleep wakeup */
51+
uint8_t prepareForS3Sleep(uint8_t lockingrange, const vector<uint8_t> &password_hash);
52+
int fd; /**< Linux handle for the device */
4853
};

linux/DtaDevLinuxNvme.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,4 @@ class DtaDevLinuxNvme: public DtaDevLinuxDrive{
5959
void * buffer, uint32_t bufferlen);
6060
/** NVMe specific routine to send an identify to the device */
6161
void identify(OPAL_DiskInfo& disk_info);
62-
int fd; /**< Linux handle for the device */
6362
};

linux/DtaDevLinuxSata.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,5 @@ class DtaDevLinuxSata: public DtaDevLinuxDrive {
5555
void * buffer, uint32_t bufferlen);
5656
/** Linux specific routine to send an ATA identify to the device */
5757
void identify_SAS(OPAL_DiskInfo *disk_info);
58-
int fd; /**< Linux handle for the device */
5958
int isSAS; /* The device is sas */
6059
};

linux/DtaDevOS.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ along with sedutil. If not, see <http://www.gnu.org/licenses/>.
3838
#include "DtaDevLinuxSata.h"
3939
#include "DtaDevLinuxNvme.h"
4040
#include "DtaDevGeneric.h"
41+
#include "DtaHashPwd.h"
42+
#include "DtaSession.h"
43+
#include "DtaDevOpal.h"
4144

4245
using namespace std;
4346

@@ -165,6 +168,36 @@ int DtaDevOS::diskScan()
165168
return 0;
166169
}
167170

171+
uint8_t DtaDevOS::prepareForS3Sleep(uint8_t lockingrange, char* password)
172+
{
173+
LOG(D1) << "Entering DtaDevOS::prepareForS3Sleep ";
174+
LOG(D2) << "Starting testing of password ";
175+
session = new DtaSession(this);
176+
if (NULL == session) {
177+
LOG(E) << "Unable to create session object ";
178+
return DTAERROR_OBJECT_CREATE_FAILED;
179+
}
180+
int err;
181+
if ((err = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) {
182+
delete session;
183+
LOG(E) << "Unable to authenticate with the given password";
184+
return err;
185+
}
186+
delete session;
187+
LOG(D2) << "Test successful, saving it to kernel ";
188+
vector<uint8_t> hash;
189+
DtaHashPwd(hash, password, this);
190+
hash.erase(hash.begin(), hash.begin()+2);
191+
192+
err = drive->prepareForS3Sleep(0, hash);
193+
if (err)
194+
{
195+
LOG(E) << "Error saving the password to the kernel errno = " << errno;
196+
return errno;
197+
}
198+
return 0;
199+
}
200+
168201
/** Close the device reference so this object can be delete. */
169202
DtaDevOS::~DtaDevOS()
170203
{

linux/DtaDevOS.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class DtaDevOS : public DtaDev {
4949
void * buffer, uint32_t bufferlen);
5050
/** A static class to scan for supported drives */
5151
static int diskScan();
52+
/** Save device key to kernel for S3 sleep resume */
53+
uint8_t prepareForS3Sleep(uint8_t lockingrange, char* password);
5254
protected:
5355
/** OS specific command to Wait for specified number of milliseconds
5456
* @param ms number of milliseconds to wait

0 commit comments

Comments
 (0)