나래온 툴 내부 구조 – 6. SATA 장치에서 기본 정보 가져오기

필요성

지난 시간에 ACS-3를 둘러보면서, 개념들과 SATA 장치에 어떻게 명령해야 하는지에 대한 방법을 살펴보았다.

이번 시간에는 나래온 툴에서 장치의 기본 정보를 얻어올 때 쓰는 명령어 구현을 살펴보자.

Identify (Identify device)

4편에서 Identify에 대해 다음과 같이 설명한 적이 있다.

BIOS나 장치 관리자에 나오는 장치 이름, 펌웨어 버전, 시리얼 번호, 용량 등은 다 여기서 가져오는 것이다. 요약하면, 단어가 보여주듯 장치의 정체에 관한 명령이다.

나래온 툴에서도, 해당 장치가 어떤 장치인지 알려면 이 명령어는 필수적이다. 위에선 네 가지 정보만 언급했지만, 실제로는 해당 저장장치가 가진 거의 모든 속성들이 identify device 명령어로 밝혀진다.

명령어를 보낼 때는 상당히 간단하다. PreviousTaskFile과 데이터 버퍼는 비우면 되고, 나머지는 다음과 같다. (N/A 역시 비우라는 뜻)

  • Passthrough 구조체의 AtaFlags: ATA_FLAGS_DATA_IN
  • CurrentTaskFile[0]: N/A
  • CurrentTaskFile[1]: N/A
  • CurrentTaskFile[2]: N/A
  • CurrentTaskFile[3]: N/A
  • CurrentTaskFile[4]: N/A
  • CurrentTaskFile[5]: N/A
  • CurrentTaskFile[6]: 0xEC
  • CurrentTaskFile[7]: N/A

정상적으로 보내졌다면 데이터 버퍼에 결과물이 오게 된다. 5편에서 언급했듯, 이는 little endian word 단위로 나오지만, string의 byte order가 특이하므로 조심해야 한다. 이 버퍼에 담긴 내용은 매우 많아 여기서 설명할 수는 없다. ACS-3의 Table 45에 20페이지 분량의 설명이 나와있으므로 참고하면 된다. 참고로 이것보다 전 버전을 볼 경우 현재 연결된 SATA 속도 관련 파트가 나와있지 않으므로 주의하라.

나래온 툴에 Identify device 명령어를 보내는 부분은 TATACommandSet의 SetBufferAndIdentifyDevice함수로 구현되어있다. 상세 함수들이 하는 일들은 위와 같으므로 굳이 모든 소스를 포함하지 않았다.

procedure TATACommandSet.SetBufferAndIdentifyDevice;
begin
  SetInnerBufferToIdentifyDevice;
  SetOSBufferByInnerBuffer;
  IoControl(TIoControlCode.ATAPassThroughDirect, IoOSBuffer);
end;

데이터 버퍼 해석은 TATABufferInterpreter의 BufferToIdentifyDeviceResult에서 하는데, 내용은 다음과 같다.

function TATABufferInterpreter.BufferToIdentifyDeviceResult(
  const Buffer: TSmallBuffer): TIdentifyDeviceResult;
begin
  BufferInterpreting := Buffer;
  result.Model := GetModelFromBuffer;
  result.Firmware := GetFirmwareFromBuffer;
  result.Serial := GetSerialFromBuffer;
  result.UserSizeInKB := GetUserSizeInKBFromBuffer;
  result.SATASpeed := GetSATASpeedFromBuffer;
  result.LBASize := GetLBASizeFromBuffer;
  result.RotationRate := GetRotationRateFromBuffer;
end;

이렇게 들어온 버퍼를 해석하는 부분 중, word로 해석하는 부분의 예시이다.

function TATABufferInterpreter.GetUserSizeInKBFromBuffer: UInt64;
const
  UserSizeStart = 100;
  UserSizeEnd = 103;
var
  CurrentWord: Integer;
begin
  result := 0;
  for CurrentWord := UserSizeStart to UserSizeEnd do
  begin
    result :=
      result +
      BufferInterpreting[CurrentWord * 2] shl
        (((CurrentWord - UserSizeStart) * 2) * 8) +
      BufferInterpreting[CurrentWord * 2 + 1]  shl
        ((((CurrentWord - UserSizeStart) * 2) + 1) * 8);
  end;
  result := result div 2;
end;

하지만 string 값은 byte order가 반대이므로 다른 예시가 필요하다.

function TATABufferInterpreter.GetModelFromBuffer: String;
const
  ModelStart = 27;
  ModelEnd = 46;
var
  CurrentWord: Integer;
begin
  result := '';
  for CurrentWord := ModelStart to ModelEnd do
    result :=
      result +
      Chr(BufferInterpreting[CurrentWord * 2 + 1]) +
      Chr(BufferInterpreting[CurrentWord * 2]);
  result := Trim(result);
end;

이렇게 이번 시간에는 SATA 장치에서 기본 정보를 가져오는 구현에 대해 살펴보았다. 다음 시간에는 더 자세한 진단 정보(SMART)를 가져오는 방법에 대해 논하려 한다.

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.