Open maenpaa24 opened 6 years ago
A few guesses. Syslinux may not have 4K sector support or the diskimage I create may not properly align to 4k sectors. I really haven't played with all the NVMe goodies so I'm probably not going to be much help.
I see, do not worry. Thank you anyway. I will post the result from two ideas that I came up with.
First, I have tried by setting the blockSize variable to 4k in file Common/DtaDevOpal.cpp (where the loadPBA function seems to be defined). Which turned out to make the process of loading the PBA image just slower, but nothing else happened.
In second place, I have tried to set bs=4k in the line where dd command is performed in the script buildUEFI64. Which remained something like this
dd if=/dev/zero of=${BUILDIMG} bs=4k count=32
This produced a smaller image file (around 130Kb or Kib, I do not remember exactly but guess it is not that important if it is a few bytes up or down) which I could load to the drive but it still did not load the PBA (I expected it not to work due to its small size compared to the built image that one can download from github)
If someone came up with an idea it would be welcomed.
Hi again!
TL,DR: I need a better understanding of the code. Could someone answer the last question? Thanks.
Following this syslinux forum https://www.syslinux.org/archives/2015-June/023545.html I would say that syslinux does support 4k sectors. So I have gone through other experiments.
I have looked for all the parts in the code where the value 512 appears to replace it with 4096:
In Common/DtaCommand.cpp:
// if (MIN_BUFFER_LENGTH + 1 > bufferpos) return(MIN_BUFFER_LENGTH);
if(bufferpos % 512)
return(((uint16_t)(bufferpos / 512) + 1) * 512);
else
return((uint16_t)(bufferpos / 512) * 512);
}
void
DtaCommand::setcomID(uint16_t comID)
In windows/DtaDiskUSB.cpp:
scsi->sd.Cdb[1] = 4 << 1; // PIO IN
scsi->sd.Cdb[2] = 0x0e;
scsi->sd.Cdb[4] = (UCHAR) (bufferlen / 512);
}
else if (IDENTIFY == cmd) {
/* Inquiry command */
scsi->sd.DataTransferLength = 512;
scsi->sd.DataIn = SCSI_IOCTL_DATA_IN;
In windows/DtaDiskUSB.cpp:
ata->CurrentTaskFile[0] = protocol; // Protocol
ata->CurrentTaskFile[1] = uint8_t(bufferlen / 512); // Payload in number of 512 blocks
LOG(D1) << "Entering DtaDiskATA::identify()";
vector<uint8_t> nullz(512, 0x00);
void * identifyResp = NULL;
identifyResp = _aligned_malloc(MIN_BUFFER_LENGTH, IO_BUFFER_ALIGNMENT);
In linux/DtaDevLinuxSata.cpp;
cdb[3] = protocol; // ATA features / TRUSTED S/R security protocol
cdb[4] = bufferlen / 512; // Sector count / transfer length (512b blocks)
// cdb[5] = reserved;
LOG(D4) << "Entering DtaDevLinuxSata::identify()";
vector<uint8_t> nullz(512, 0x00);
uint8_t * buffer = (uint8_t *) memalign(IO_BUFFER_ALIGNMENT, MIN_BUFFER_LENGTH);
In images/buildbios:
dd if=../scratch/${SYSLINUX}/bios/mbr/mbr.bin of=${BUILDIMG} count=1 conv=notrunc bs=512
LOOPDEV=`sudo losetup --show -f -o 1048576 ${BUILDIMG}`
In images/legacypba:
(echo o;echo n;echo p;echo 1;echo 63;echo "";echo a;echo 1;echo t;echo b;echo w) | fdisk -C 10 ${BUILDIMG}
dd if=${SYSLINUX_PBA}/bios/mbr/mbr.bin of=${BUILDIMG} count=1 conv=notrunc bs=512
In windows/PSIDRevert_WINDOWS.txt:
Align = Y, Alignment Granularity = 8 (4096), Logical Block size = 512, Lowest Aligned LBA = 0
SingleUser function (0x0201)
ALL = N, ANY = N, Policy = Y, Locking Objects = 9
In Common/DtaStructures.h:
unsigned m_Reserved_1 : 7; // 4
unsigned m_INC_512 : 1;
uint8_t m_Reserved_2; // 5
In linux/PSIDRevert_LINUX.txt:
Geometry function (0x0003)
Align = Y, Alignment Granularity = 8 (4096), Logical Block size = 512, Lowest Aligned LBA = 0
In images/buildrescue:
dd if=../scratch/${SYSLINUX}/bios/mbr/mbr.bin of=${BUILDIMG} count=1 conv=notrunc bs=512
else
echo "n";echo "";echo "";echo "";echo "ef00";echo w;echo Y) | gdisk ${BUILDIMG}
In Common/DtaCommand.h:
/** Return the space used in the command buffer (rounded to 512 bytes) */
uint16_t outputBufferSize();
private:
/** return a pointer to the command buffer */
In images/buildroot/32bit/.config:
# Legacy options removed in 2015.05
#
# BR2_TARGET_ROOTFS_JFFS2_NANDFLASH_512_16K is not set
# BR2_TARGET_ROOTFS_JFFS2_NANDFLASH_2K_128K is not set
# BR2_PACKAGE_MONO_20 is not set
In images/buildroot/64bit/.config:
# BR2_TARGET_UBOOT_NETWORK is not set
#
# Legacy options removed in 2015.05
#
# BR2_TARGET_ROOTFS_JFFS2_NANDFLASH_512_16K is not set
Sadly just replacing 512 by 4096 everywhere didn't work.
After that, I went to the buildUEFI64 and buildrescue scripts. Especially the buildUEFI64 which is the one that creates the image that is copied in to the shadow MBR as the PBA. I changed the line:
sudo losetup --show -f -o 1048576 ${BUILDIMG}
by
sudo losetup --show -f -o 1048576 -b 4096 ${BUILDIMG}
so that the loop device would be 4k as well. I did not change the offset value because it should work as far as the number of sector that it translates to is greater than the firs usable sector on the disk, which in this case seems to be 6 in 4k and 34 in 512.
It didn't work either. So I went to study the part of the code where the function loadPBA is defined, this is, the file Common/DtaDevOpal.cpp. Here I lack the proper knowledge about how the tcg opal communication protocol works, and I have not found good literature to understand it. I only found the specifications pdfs such as https://www.trustedcomputinggroup.org/wp-content/uploads/TCG_Storage-Opal_SSC_v2.01_rev1.00.pdf but I can't find any information related to this in those pdfs.
If someone could provide or inform about some good literature on the topic it would be really welcomed. With that said, I tried to understand it and I could barely guess the following:
blockSize -= sizeof(OPALHeader) + 50; // packet overhead
might the OPALHeader depend on the sector size somehow?
Other than that, I think that the key could be here:
lengthtoken.clear();
lengthtoken.push_back(0xe2);
lengthtoken.push_back((uint8_t) ((blockSize >> 16) & 0x000000ff));
lengthtoken.push_back((uint8_t)((blockSize >> 8) & 0x000000ff));
lengthtoken.push_back((uint8_t)(blockSize & 0x000000ff));
pbafile.read((char *)buffer.data(), blockSize);
cmd->reset(OPAL_UID::OPAL_MBR, OPAL_METHOD::SET);
cmd->addToken(OPAL_TOKEN::STARTLIST);
cmd->addToken(OPAL_TOKEN::STARTNAME);
cmd->addToken(OPAL_TOKEN::WHERE);
cmd->addToken(filepos);
cmd->addToken(OPAL_TOKEN::ENDNAME);
cmd->addToken(OPAL_TOKEN::STARTNAME);
cmd->addToken(OPAL_TOKEN::VALUES);
cmd->addToken(lengthtoken);
cmd->addToken(buffer);
cmd->addToken(OPAL_TOKEN::ENDNAME);
cmd->addToken(OPAL_TOKEN::ENDLIST);
cmd->complete();
However I do not really understand why the value 0xe2 is required at the begining of the lengthtoken and I can not figure out what of all that depends on the sector size.
Finally, another fact that I do not really understand is the fact that when the disk is formated in 512b sectors, fdisk -l shows that the pba partition starts in sector 2048 and ends in sector 65502, a total of 30.9MB. While when de disk is formated in 4k sectors the pba partition starts in sector 1 and ends in sector 65535, a total of 255MB.
Where in the code are this starting sector and end sector calculated? I think the fix should be just tweaking that part.
Another interesting fact is that fdisk can see the partition /dev/nvme0n1p1. However, such partituon does not appear in /dev folder and, of course, it can not be mounted. Gdisk can not see the partition. Again, if formated in 512b sectors, the partition is indeed in the /dev folder and can be mounted.
Any aid would be welcomed.
Hi!
If the nvme ssd drive is formatted in 4k sectors the PBA will not boot, whereas if it is formatted in 512b sector size it will boot and unlock the drive properly. Tested on a Toshiba THNSF5512GPUK on a MacBook Pro 13 early 2015 with sedutil 1.15.1. I suppose the problem is the PBA written in 4k sectors rather than the macbook boot loader because the macbook is able too boot Mac OS and linux from the nvme ssd drive while this is formatted in 4k sectors.
PS: when the drive is formatted in 4k sectors it can be unlocked with the linuxPBA written onto a 512b sector pendrive.
Any aid is welcome, regards.