Jump to content
Jief_Machak

Filevault 2 (FV2) with ps2 keyboard

38 posts in this topic

Recommended Posts

The BiosKeyboard driver is now compatible with FV2.

Currently it's only working with Legacy boot. To make it work with UEFI, I tried to disconnect the keyboard and load the new driver but this hangs. Don't know why. Any idea ?

If anyone want to work on this with me, can we create a branch and work on it ?

 

To experiment connection and disconnection of UEFI drivers, efi shell is handy. Unfortunately efi shell doesn't launch on my laptop when Clover is booted from UEFI. I can see the switch to text mode and then nothing. Works if Clover booted legacy. Any idea ?

 

Jief

 

Attached is my BiosKeyboard.c. 

BiosKeyboard.c

Share this post


Link to post
Share on other sites
Advertisement

Shell requires UnicodeCollation protocol that already present with legacy Clover but may absent with your UEFI.

Use EnglishDxe.efi driver in drivers64U folder.

I will look your BiosKeyboard and commit it.

Share this post


Link to post
Share on other sites

AMI drivers are {censored}ed and disconnecting will break stuff on Aptio IV. I don't think it can be avoided properly, but to not have it connect in the first place (-> flashing).

I wonder why AptioInputFix does not work with PS/2 in the first place, AMI only exposes one protocol iirc

 

EDIT: Flashing might now work afterall. I kind of forgot in what way exactly the AMI driver was {censored}ed up.

EDIT2: nvm, flashing should work.

Edited by Download-Fritz

Share this post


Link to post
Share on other sites

The AMI driver is a HID driver (I don't know if the exact issues present for USB apply to PS/2 the same way, but I guess so) and flashing means integrating the driver into your UEFI image and flashing that.

Share this post


Link to post
Share on other sites

You mean repack my laptop firmware and flashing that back to laptop firmware ?

No idea how that can be done but if I could replace the ps2 driver by my version, sure it should work. Is there tools to extract all efi modules from original firmware and repack them ?

Share this post


Link to post
Share on other sites
On 5/25/2018 at 4:05 PM, Slice said:

Shell requires UnicodeCollation protocol that already present with legacy Clover but may absent with your UEFI.

Use EnglishDxe.efi driver in drivers64U folder.

I will look your BiosKeyboard and commit it.

Great, thanks. EnglishDxe.efi make it works.

Share this post


Link to post
Share on other sites

Reflash my firmware wasn't my first choice because the flash memory chip has its pins behind itself, so I have to unsolder to flash it.

I would have been happy to keep a legacy boot, but I discover 2 days ago that my laptop doesn't want to legacy boot a gpt partitionned drive ! Bummer.

I spent a day trying to disconnect ps2 keyboard from its uefi driver to reconnect it to the one loaded by clover : it hangs each time. I think it hangs in LegacyBiosInt86 in AsmThunk16.

 

So I scratch my head and found another solution. I wrote this AppleKeyFeeder.efi. Just put it in drivers64UEFI. Remove any keyboard driver you have in drivers64UEFI (usb and ps2).

 

It currently works in VMWare and on my laptop. Works with ps2 and usb (plugged at boot or later) keyboards. I think that should solve the problem of disconnecting and reconnecting usb keyboard.

 

whew, wasn't an easy one... :surprised:

 

Edited by Jief_Machak

Share this post


Link to post
Share on other sites

Hi, I have not checked it out yet, but does it work similarly to our AptioInputFix (https://github.com/vit9696/AptioFixPkg/tree/master/Platform/AptioInputFix) except proxies some other interface? If so, does it work with mac hotkeys (cmd+r, cmd+s, 3+2, and so on)? It was one of the hardest parts when I proxied the AMI protocol, and it is still very imperfect.

Share this post


Link to post
Share on other sites

It definitely work with UEFI. AppleKeyFeeder would work legacy, but currently, BiosKeyboard and UsbKbDxe send keys to AppleKeyMap, so it will conflict. Well, not really conflict. I didn't test it, but you should get keystroke twice in Apple efi preboot env.

It didn't even test hotkeys because it is just to enter a password. Is there any hotkeys available at preboot on real mac ?

 

Anyone likes game ? Any guess an how it works, before I publish the sources ? :) (I'm proud of the little trick I used :yes:)

Edited by Jief_Machak

Share this post


Link to post
Share on other sites

I just tried AppleKeyFeeder and can confirm that it works on a ThinkPad T470 to unlock FV2, where AptioFixInput doesn't work! Thank you very much for the effort :)

Share this post


Link to post
Share on other sites

Jief_Machak, ok, if you insist on checking the code without sources...

 

You have 2 events created on startup:

EFI_STATUS InstallEvents()
{
  gBS->CreateEvent(0x80000200, 0x10ui64, (EFI_EVENT_NOTIFY)CleanupBuffer, 0i64, &gCleanupBufferEvent);
  gBS->CreateEvent(0x80000200, 0x10ui64, (EFI_EVENT_NOTIFY)FillBuffer, 0i64, &gFillBufferEvent);
  return gBS->SetTimer(gFillBufferEvent, TimerPeriodic, 300000ui64);
}

One event (gFillBufferEvent) is meant to feed the values to the keystroke buffer, and is called every 0.3 microseconds.

This event invokes gST->ConIn's ReadKeyStroke (implemented via ConSplitter), and tries to read any keystroke currently present.

There is a somewhat functioning key mapping from EFI_INPUT_KEY to APPLE_KEY_CODE in FillBuffer, and after a keystroke submit it sets a timer of 0.15 microseconds to a second event (gCleanupBufferEvent), which erases the keystroke buffer to avoid key repeat.

 

Unfortunately, while this naive approach indeed does work for a very limited set of cases, it has many flaws, and that for this reason I, Fritz, and Ozmozis guys (at least from what I know) had to go a level deeper to the keyboard driver. For example:

1. EFI_INPUT_KEY does not give you enough details about the modifiers. The only modifier currently supported in your approach is left shift, and you cannot obtain any info about Command, Ctrl or others. This is important to get verbose boot via Cmd+V, for example.

2. EFI_INPUT_KEY only passes you a functional key, not the modifier. So pressing and holding Shift will not result in a keystroke, and as a result you will not boot into Safe Mode. I think on some implementations key there was no KeyStoke on holding the key, so automatic key repeat would also be broken.

3. A USB (and a PS2) driver submits you key down/key up events, allowing the proper handling of the keybuffer, so you could press and hold 3+2 and it will boot into 32-bit mode on 10.7 with UsbKbDxe.

 

Another issue is that it races with other apps like UEFI Shell, Clover Menu, etc, when UsbKbDxe does not. This results in missed keys and input issues, which is a little undesired.

 

All in all… thanks for the input, it definitely works for really broken systems, when neither UsbKbDxe, nor AptioInputFix works, but I guess there is no room for any improvement.

 

 

/* This file has been generated by the Hex-Rays decompiler.
   Copyright (c) 2007-2018 Hex-Rays <info@hex-rays.com>

   Detected compiler: Visual C++
*/

#include <defs.h>


//-------------------------------------------------------------------------
// Function declarations

void sub_240();
EFI_STATUS __fastcall SetBootServices(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
EFI_STATUS __fastcall SetRuntimeServices(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
__int64 ReturnSuccess();
__int64 __fastcall sub_721(__int64 a1);
EFI_STATUS __cdecl ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
EFI_STATUS InstallEvents();
EFI_STATUS CleanupBuffer();
EFI_STATUS FillBuffer();
EFI_STATUS __fastcall InstallHandles(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
void InstallEventsFailure();
EFI_STATUS InstallEventsWrapper();
EFI_STATUS __cdecl Unused1();

//-------------------------------------------------------------------------
// Data declarations

EFI_GUID gAppleKeyMapDatabaseProtocolGuid =
{
  1481350846u,
  32961u,
  19414u,
  { 152u, 176u, 167u, 120u, 110u, 194u, 242u, 226u }
};
EFI_HANDLE gImageHandle = &_ImageBase;
EFI_SYSTEM_TABLE *gST = &_ImageBase;
EFI_BOOT_SERVICES *gBS = &_ImageBase;
EFI_RUNTIME_SERVICES *gRT = &_ImageBase;
APPLE_KEY_MAP_DATABASE_PROTOCOL *gKeyMap = &_ImageBase;
UINTN gKeyMapDbIndex = 0ui64;
EFI_EVENT gCleanupBufferEvent = &_ImageBase;
EFI_EVENT gFillBufferEvent = &_ImageBase;


//----- (0000000000000240) ----------------------------------------------------
void sub_240()
{
  ;
}

//----- (0000000000000695) ----------------------------------------------------
EFI_STATUS __fastcall SetBootServices(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  gImageHandle = ImageHandle;
  gST = SystemTable;
  gBS = SystemTable->BootServices;
  return 0i64;
}

//----- (0000000000000706) ----------------------------------------------------
EFI_STATUS __fastcall SetRuntimeServices(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  gRT = SystemTable->RuntimeServices;
  return 0i64;
}

//----- (0000000000000719) ----------------------------------------------------
__int64 ReturnSuccess()
{
  return 0i64;
}

//----- (0000000000000721) ----------------------------------------------------
__int64 __fastcall sub_721(__int64 a1)
{
  signed __int64 v1; // rsi

  v1 = Unused1();
  if ( v1 >= 0 )
    InstallEventsFailure();
  return v1;
}

//----- (0000000000000755) ----------------------------------------------------
EFI_STATUS __cdecl ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  EFI_STATUS Status; // rbx

  InstallHandles(ImageHandle, SystemTable);
  Status = InstallEventsWrapper();
  if ( (Status & 0x8000000000000000ui64) != 0i64 )
    InstallEventsFailure();
  return Status;
}

//----- (00000000000007EC) ----------------------------------------------------
EFI_STATUS InstallEvents()
{
  gBS->CreateEvent(0x80000200, 0x10ui64, (EFI_EVENT_NOTIFY)CleanupBuffer, 0i64, &gCleanupBufferEvent);
  gBS->CreateEvent(0x80000200, 0x10ui64, (EFI_EVENT_NOTIFY)FillBuffer, 0i64, &gFillBufferEvent);
  return gBS->SetTimer(gFillBufferEvent, TimerPeriodic, 300000ui64);
}

//----- (000000000000086D) ----------------------------------------------------
EFI_STATUS CleanupBuffer()
{
  char v1; // [rsp+2Eh] [rbp-2h]

  gKeyMap->SetKeyStrokeBufferKeys(gKeyMap, gKeyMapDbIndex, 0, 0i64, (UINT16 *)&v1);
  return gBS->SetTimer(gCleanupBufferEvent, 0, 10000ui64);
}

//----- (00000000000008B4) ----------------------------------------------------
EFI_STATUS FillBuffer()
{
  EFI_STATUS Status; // rax
  UINT16 ScanCode; // di
  CHAR16 UnicodeChar; // si
  APPLE_KEY_MAP_DATABASE_PROTOCOL *KeyMap; // rcx
  __int16 v4; // si
  UINT16 CurrentModifiers; // r8
  EFI_INPUT_KEY KeyStroke; // [rsp+28h] [rbp-18h]
  __int16 CurrentKeys; // [rsp+2Eh] [rbp-12h]

  Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &KeyStroke);
  if ( (Status & 0x8000000000000000ui64) == 0i64 )
  {
    ScanCode = KeyStroke.ScanCode;
    UnicodeChar = KeyStroke.UnicodeChar;
    KeyMap = gKeyMap;
    if ( gKeyMap )
      goto KEY_MAP_EXISTS;
    Status = gBS->LocateProtocol(&gAppleKeyMapDatabaseProtocolGuid, 0i64, (void **)&gKeyMap);
    if ( (Status & 0x8000000000000000ui64) == 0i64 )
      Status = gKeyMap->CreateKeyStrokesBuffer(gKeyMap, 6ui64, &gKeyMapDbIndex);
    KeyMap = gKeyMap;
    if ( gKeyMap )
    {
KEY_MAP_EXISTS:
      if ( UnicodeChar )
      {
        if ( (unsigned __int16)(UnicodeChar - 0x61) <= 0x19u )
        {
          v4 = UnicodeChar + 0x6FA3;
LABEL_9:
          CurrentKeys = v4;
LABEL_10:
          CurrentModifiers = 0;
SET_KEY:
          KeyMap->SetKeyStrokeBufferKeys(KeyMap, gKeyMapDbIndex, CurrentModifiers, 1ui64, (UINT16 *)&CurrentKeys);
          return gBS->SetTimer(gCleanupBufferEvent, TimerPeriodic, 150000ui64);
        }
        if ( (unsigned __int16)(UnicodeChar - 65) <= 0x19u )
        {
          CurrentKeys = UnicodeChar + 28611;
DO_SET_KEY:
          CurrentModifiers = 2;                 // Shift
          goto SET_KEY;
        }
        if ( UnicodeChar == '0' )
        {
          CurrentKeys = 0x7027;
          goto LABEL_10;
        }
        if ( (unsigned __int16)(UnicodeChar - 49) <= 8u )
        {
          v4 = UnicodeChar + 0x6FED;
          goto LABEL_9;
        }
        Status = (unsigned __int16)(UnicodeChar - 1);
        switch ( (_DWORD)Status )
        {
          case 0:
            goto LABEL_14;
          case 1:
            goto LABEL_23;
          case 2:
            goto LABEL_24;
          case 3:
            goto LABEL_25;
          case 4:
          case 5:
          case 6:
          case 8:
          case 9:
          case 0xA:
          case 0xB:
          case 0xD:
          case 0xE:
          case 0xF:
          case 0x10:
          case 0x11:
          case 0x12:
          case 0x13:
          case 0x14:
          case 0x15:
          case 0x16:
          case 0x17:
          case 0x18:
          case 0x19:
          case 0x1A:
          case 0x1B:
          case 0x1C:
          case 0x1D:
          case 0x1E:
          case 0x2F:
          case 0x30:
          case 0x31:
          case 0x32:
          case 0x33:
          case 0x34:
          case 0x35:
          case 0x36:
          case 0x37:
          case 0x38:
            return Status;
          case 7:
            CurrentKeys = 28714;
            goto LABEL_10;
          case 0xC:
            CurrentKeys = 28712;
            goto LABEL_10;
          case 0x1F:
            CurrentKeys = 28716;
            goto LABEL_10;
          case 0x20:
            CurrentKeys = 28702;
            goto DO_SET_KEY;
          case 0x21:
            CurrentKeys = 28724;
            goto DO_SET_KEY;
          case 0x22:
            CurrentKeys = 28704;
            goto DO_SET_KEY;
          case 0x23:
            CurrentKeys = 28705;
            goto DO_SET_KEY;
          case 0x24:
            CurrentKeys = 28706;
            goto DO_SET_KEY;
          case 0x25:
            CurrentKeys = 28708;
            goto DO_SET_KEY;
          case 0x26:
            CurrentKeys = 28724;
            goto LABEL_10;
          case 0x27:
            CurrentKeys = 28710;
            goto DO_SET_KEY;
          case 0x28:
            CurrentKeys = 28711;
            goto DO_SET_KEY;
          case 0x29:
            CurrentKeys = 28709;
            goto DO_SET_KEY;
          case 0x2A:
            CurrentKeys = 28718;
            goto DO_SET_KEY;
          case 0x2B:
            CurrentKeys = 28726;
            goto LABEL_10;
          case 0x2C:
            CurrentKeys = 28717;
            goto LABEL_10;
          case 0x2D:
            CurrentKeys = 28727;
            goto LABEL_10;
          case 0x2E:
            CurrentKeys = 28728;
            goto LABEL_10;
          case 0x39:
            CurrentKeys = 28723;
            goto DO_SET_KEY;
          case 0x3A:
            CurrentKeys = 28723;
            goto LABEL_10;
          case 0x3B:
            CurrentKeys = 28726;
            goto DO_SET_KEY;
          case 0x3C:
            CurrentKeys = 28718;
            goto LABEL_10;
          case 0x3D:
            CurrentKeys = 28727;
            goto DO_SET_KEY;
          case 0x3E:
            CurrentKeys = 28728;
            goto DO_SET_KEY;
          case 0x3F:
            CurrentKeys = 28703;
            goto DO_SET_KEY;
          default:
            switch ( (unsigned __int16)(UnicodeChar - 91) )
            {
              case 0u:
                CurrentKeys = 28719;
                goto LABEL_10;
              case 1u:
                CurrentKeys = 28721;
                goto LABEL_10;
              case 2u:
                CurrentKeys = 28720;
                goto LABEL_10;
              case 3u:
                CurrentKeys = 28707;
                goto DO_SET_KEY;
              case 4u:
                CurrentKeys = 28717;
                goto DO_SET_KEY;
              case 5u:
                CurrentKeys = 28725;
                goto LABEL_10;
              default:
                Status = (unsigned __int16)(UnicodeChar - 123);
                switch ( (_DWORD)Status )
                {
                  case 0:
                    CurrentKeys = 28719;
                    goto DO_SET_KEY;
                  case 1:
                    CurrentKeys = 28721;
                    goto DO_SET_KEY;
                  case 2:
                    CurrentKeys = 28720;
                    goto DO_SET_KEY;
                  case 3:
                    CurrentKeys = 28725;
                    goto DO_SET_KEY;
                  default:
                    return Status;
                }
            }
        }
      }
      else
      {
        Status = (unsigned __int16)(ScanCode - 1);
        switch ( (_DWORD)Status )
        {
          case 0:
LABEL_14:
            CurrentKeys = 0x7052;
            goto LABEL_10;
          case 1:
LABEL_23:
            CurrentKeys = 0x7051;
            goto LABEL_10;
          case 2:
LABEL_24:
            CurrentKeys = 0x7050;
            goto LABEL_10;
          case 3:
LABEL_25:
            CurrentKeys = 0x704F;
            goto LABEL_10;
          default:
            return Status;
        }
      }
    }
  }
  return Status;
}

//----- (0000000000000D24) ----------------------------------------------------
EFI_STATUS __fastcall InstallHandles(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  SetBootServices(ImageHandle, SystemTable);
  SetRuntimeServices(ImageHandle, SystemTable);
  return ReturnSuccess();
}

//----- (0000000000000D56) ----------------------------------------------------
void InstallEventsFailure()
{
  ;
}

//----- (0000000000000D5C) ----------------------------------------------------
EFI_STATUS InstallEventsWrapper()
{
  return InstallEvents();
}

//----- (0000000000000D66) ----------------------------------------------------
EFI_STATUS __cdecl Unused1()
{
  return 0i64;
}

// ALL OK, 13 function(s) have been successfully decompiled

 

Edited by vit9696

Share this post


Link to post
Share on other sites

@vit9696 I didn't insist on anything. I wasn't challenging anyone. I apologize if it was taken that way.

 

It's not a naive approach. I started the way it's logical, improving BiosKeyboard to handle AppleKeyMap. I agree, it should be the way.

But I can't replace my UEFI ps2 keyboard. So I have to do it an other way. Yes, in that version, it races, and you lose some keystroke. In reality, it works well in Clover, barely losing a keystroke (and Clover isn't meant to type a lot, is it?). But, true, it works badly in UEFI shell.

 

There is no room for improvement ?... Well, there is. Here is a version that doesn't race. I got the inspiration in your AptioInputFix sources. Thanks.

 

EDIT : removed attachment. Wrong file.

 

Edited by Jief_Machak

Share this post


Link to post
Share on other sites

@mauritzius Thanks for the feedback. Appreciate it.

Could confirm that the version you've downloaded works not well in UEFI shell, and then tried the 3rd version ?

 

Thanks.

Edited by Jief_Machak

Share this post


Link to post
Share on other sites

I've tested efi from the post "Small bug corrected : 2nd version AppleKeyFeeder.efi"

It works nicely ! I don't have to plug an USB keyboard to type my passphrase to unlock FV2 anymore.

 

My config is a Lenovo x260 (based on tluck t460 w/ Clover EFI), PS2 keyboard was working in Clover but not for FV2 passphrase before that

Share this post


Link to post
Share on other sites
11 hours ago, Jief_Machak said:

@vit9696 I didn't insist on anything. I wasn't challenging anyone. I apologize if it was taken that way.

 

It's not a naive approach. I started the way it's logical, improving BiosKeyboard to handle AppleKeyMap. I agree, it should be the way.

But I can't replace my UEFI ps2 keyboard. So I have to do it an other way. Yes, in that version, it races, and you lose some keystroke. In reality, it works well in Clover, barely losing a keystroke (and Clover isn't meant to type a lot, is it?). But, true, it works badly in UEFI shell.

 

There is no room for improvement ?... Well, there is. Here is a version that doesn't race. I got the inspiration in your AptioInputFix sources. Thanks.

AppleKeyFeeder.efi

Am I blind or do you not recalculate the gST CRC?

Also, what toolchain/optimization level are you using? Looks like O0 or some borked setup, there is quite some trash in there

Share this post


Link to post
Share on other sites

That is my first efi module. If the module have to calculate some CRC, you're welcome to tell me. But yes, I don't recalculate anything so far. I didn't find much documentation, sorry.

If I didn't do a mistake when attaching the file, the 3rd version was compiled with edk2 build system, using "--xcode5" parameter.

 

I may have given my development version before. Which was compiled by eclipse/gcc, using -O0 for interactive debugging in eclipse.

Sources will be on my github very soon.

Share this post


Link to post
Share on other sites

The second version works on Lenovo V580, though with a long delay. The third version does not work.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×