UEFI development exploration 80- YIE001PCIe development board (final migration essay)

(please keep it - > Author: Luo Bing https://blog.csdn.net/luobing4365)

After a rough count, at least 50 demonstration programs of various UEFI have been developed in the blog. In theory, most of the code can actually be transplanted to the Option ROM of YIE001 development board.

However, the ch366 chip used in YIE001 only supports program files with a window capacity of 32K (of course, it can be extended through the I2C two-wire serial port of ch366). In this case, some restrictions are set on the writing of code.

This article will take the example MyGuiFrame in Chapter 6 of UEFI programming practice as the blueprint and transplant it to the Option ROM framework code of YIE001. This example is in the warehouse https://gitee.com/luobing4365/uefi-practical-programming.git / RobinPkg\Applications\MyGuiFrame. (it is still being sorted out and has not been uploaded to the warehouse, by robin,20210215)

1. Considerations for option ROM development

The development board YIE001 is mainly used for the development of Option ROM. due to the limitations of PCIE chip CH366 and Option ROM under UEFI, there are still many places to pay attention to in writing code. From my point of view, I need to pay attention to the following points.

1) Reduce the size of the generated file

After all, the window capacity of YIE001 is only 32K, and the amount of code it can hold is limited. And because the code is written in C language, it is difficult to accurately calculate the size of the generated file. We must pay attention to the size of the code.

Therefore, the first rule is to try to use the library functions provided by EDK2. Do not use functions provided by external libraries, such as StdLib library. Using encapsulated library functions will increase the size of the generated file. Among the library functions provided by EDK2 itself, common functions such as memory processing and string processing are provided. Try to use these functions as much as possible.

In the development, the most occupied space is the image, Chinese character font and other resources. Generally speaking, you should draw your own images using graphics functions as much as possible, and use standard images as little as possible for display. The second rule is that the graphical interface should be as simple as possible. The Chinese character library should adopt the technology of small character library, that is, the character library of these Chinese characters should be extracted according to which Chinese characters are used.

In previous blogs, a lot of space has been spent on the display of Chinese characters, graphics and images. You can check the corresponding chapters.

Of course, some lossless compression algorithms can also be used to compress resources. However, I think it is difficult to compress in 32K space and accommodate large files. If you are interested in the same technology, you can try it.

2) Try to use load or loadpcirom

The most impressive project I took over was to build the Option ROM program myself and embed it into the BIOS. The biggest headache is that the program ran away during operation, resulting in the BIOS unable to start the disk.

The code of YIE001 is in Flash. Of course, it will not seriously affect the BIOS startup. At most, remove the YIE001 board from the PCIe slot and start it again.

However, the problems in both cases are similar. If you brush the Option ROM code into the Flash ROM of YIE001, if there is no effective exit mechanism, it is likely that the U SB flash disk or other startup disks cannot be started when the board is inserted in the PCIe slot, resulting in the inability to re brush the program.

Therefore, when brushing the ROM file into the Flash ROM of YIE001, first conduct a complete test under the UEFI Shell to ensure that there are no problems before brushing in.

The third rule is to test the ROM file under UEFI Shell and then brush it into Flash ROM.

3) There must always be a means of exit

This is to strengthen the above rules and provide exit means in the program code. The fourth rule is that there should always be exit means when programming.

Even if the UEFI Shell test passes the ROM file, the Protocol called by the program cannot be guaranteed to work well when the Option ROM is running.

Therefore, before starting to run the main programs in Option ROM, users should be allowed to exit Option ROM by some means, such as judging by pressing keys.

Of course, these rules are for programmers learning Option ROM. if you are developing commercial products, you can certainly directly use the programmer to write Flash ROM. please ignore these rules.

4) Remember UP32K#

If you still accidentally brush in the problem ROM file and cannot exit, resulting in failure to start the U SB flash disk, YIE001 also reserves the last means, namely UP32K#.

This is the mechanism provided by switching to another 32K window code on CH366. CH366 supports two sets of completely independent 32KB main programs, which are selected by the state of UP32K# pin during reset.

Generally, the toggle switch ON the UP32K # pin (marked "UP32K #" ON the board) is far away from the "ON" end. If the U SB flash disk cannot be started due to Option ROM, you can turn the toggle switch to the "ON" end when starting up.

When entering the DOS startup disk (ready to brush Flash ROM), turn the toggle switch of UP32K# to be far away from the "ON" end. At this time, you can brush again.

Note that UP32K # in different states corresponds to different 32K spaces in Flash ROM. The above method only uses the 32K near the "ON" end and has not written code. Therefore, when you toggle the UP32K # switch, you must remember the corresponding position when brushing.

The above rule is summarized as Article 5: remember UP32K#.

To sum up, write Option ROM on YIE001 and remember five rules:
(1) Try to use the library functions provided by EDK2;
(2) The graphical interface should be as simple as possible, and the technology of small font library should be adopted in the Chinese character library;
(3) Test the ROM file under UEFI Shell, and then brush it into Flash ROM;
(4) Always have exit means when programming;
(5) Remember UP32K#.

If the Flash ROM of YIE001 cannot be redrawn, the programmer can only be used to redraw the Flash ROM.

2 Introduction to myguiframe

The following will take MyGuiFrame as an example to introduce how to transplant the previously written UEFI application to the Option ROM framework.

The MyGuiFrame I built is a simple GUI framework under UEFI, which mainly realizes the following functions:
(1) Establish an overall event handling mechanism to unify mouse events, keyboard events, and events that regularly check interface messages under the same management mechanism;
(2) Handle mouse initialization and corresponding mouse drawing;
(3) Handle keyboard events and handle keyboard keys;

In other words, the events to be processed include three events: mouse event, keyboard event and timer event. Among them, timer events are prepared to establish a complete message mechanism to connect graphical controls with processing functions.

2.1 GUI event management

The GUI management framework for responding to events is as follows:

EFI_EVENT gTimerEvent;
EFI_EVENT gWaitArray[3];
VOID InitGUI(VOID)  //Initialize GUI events and other initialization work
{
  gBS->CreateEvent(EVT_TIMER,TPL_APPLICATION,(EFI_EVENT_NOTIFY)NULL,              
                      (VOID*)NULL,&gTimerEvent);//Create timer event
  gBS->SetTimer(gTimerEvent,TimerPeriodic,10*1000*1000);//Set to trigger per second 
  gWaitArray[EVENT_TIMER]=gTimerEvent;            //The event array element 0 is a timer
  gWaitArray[EVENT_KEY]=gST->ConIn->WaitForKey; //Event array element 1 is a keyboard event
  gWaitArray[EVENT_MOUSE]=gMouse->WaitForInput; //Event array element 2 is a mouse event
  initMouseArrow();   //Initialize mouse                                
}
VOID HanlderGUI(VOID) //Handling of various GUI events
{
  UINTN Index;
  EFI_INPUT_KEY key={0,0};
  EFI_SIMPLE_POINTER_STATE mouseState;
  while(1)
  {
    gBS->WaitForEvent(3, gWaitArray, &Index);
    if(Index == EVENT_KEY)  //Handle keyboard events
    {
      gST->ConIn->ReadKeyStroke(gST->ConIn,&key);
      HandlerKeyboard(&key);
    }
    else if(Index == EVENT_MOUSE) //Handle mouse events
    {
      GetMouseState(&mouseState);
      HandlerMouse(&mouseState);
    }
    else if(Index == EVENT_TIMER) //Processing timer events
    {
      HandlerTimer();
    }
    else{  }//Unexpected error handling    
  }
}

In the event processing framework, timer events triggered every 1 second are set. Together with mouse events and keyboard events, it forms an event array. In the framework of event management, these three events are handled separately.

In practical applications, timer events can be used to traverse the real-time refresh and message processing of graphical elements such as GUI controls and dialog boxes. It is certain that the refresh time cannot be set to 1 second to trigger. Such a slow speed cannot meet the demand. The minimum timer event of UEFI can be set to 100ns trigger, which can meet the very real-time picture refresh.

In the actual event management framework, multiple timers can be set to meet the application requirements. The example only sets a timer, which is mainly used to demonstrate the function of the framework. The event processing function will display a string on the screen every 1 second. The code is as follows:

EFI_STATUS HandlerTimer(VOID)
{
  static UINT8 flag=0;
  UINT8 *s_text = "Timer Event has triggered.";  
  if(flag==1)
  {
    flag=0;
    draw_string(s_text, 100, 150, &MyFontArray, &(gColorTable[WHITE]));
  }
  else
  {
    flag=1;
    rectblock(100,150,400,180,&(gColorTable[DEEPBLUE]));//Eliminate strings with background color
  }
  return EFI_SUCCESS;
}

2.2 mouse event handling

Mouse is a relatively special part of GUI framework. Its event processing involves the drawing of mouse image, the acquisition of mouse position and the processing of mouse buttons.

In order to realize the drawing of the mouse, an 18x25 mouse pattern is prepared in the example project MyGuiFrame, which is extracted and saved in PCX image format. You can directly call the PCX image display function in section 5.1.2 to draw the mouse.

The implementation code is as follows:

VOID putMouseArrow(UINTN x,UINTN y)
{
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer1;
  UINT32 BltBufferSize;
  if(x>=(SY_SCREEN_WIDTH-1-gMouseWidth)) //Limit the mouse x coordinate to no more than the screen
    x=SY_SCREEN_WIDTH-1-gMouseWidth;
  if(y>=SY_SCREEN_HEIGHT-1-gMouseHeight) //The mouse y coordinate displayed does not exceed the screen
    y=SY_SCREEN_HEIGHT-1-gMouseHeight;
  //1 oldZone contains the area covered by the last mouse display. Restore the image of this area
  putRectImage(mouse_xres,mouse_yres,gMouseWidth,gMouseHeight,oldZone);
  mouse_xres=(UINT16)x; //Mouse x coordinate
  mouse_yres=(UINT16)y; //Mouse y coordinate
  getRectImage(x,y,gMouseWidth,gMouseHeight,oldZone); //Save the current mouse coverage
  //2 display the mouse at the current position
  BltBufferSize = ((UINT32)gMouseWidth *  (UINT32)gMouseHeight * (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)));
  BltBuffer = AllocateZeroPool(BltBufferSize);
  BltBuffer1 = AllocateZeroPool(BltBufferSize);
  getRectImage(x,y,gMouseWidth,gMouseHeight,BltBuffer); 
  decompressPCX256_special(gMouseWidth,gMouseHeight,
  gMousePicColorTable,gMousePicPicture,BltBuffer1,1);
  //Transparent processing and display
  MaskingTransparent(gMouseWidth,gMouseHeight,BltBuffer1,BltBuffer,10);
  putRectImage(x,y,gMouseWidth,gMouseHeight,BltBuffer);
  FreePool(BltBuffer); 
  FreePool(BltBuffer1);              
}

The process of mouse drawing is to continuously restore the content covered by the previous mouse, save the content to be covered by the current mouse, and draw the mouse pattern at the specified current position.

In the function of mouse event processing, it mainly draws the mouse pattern. Moreover, it mainly deals with the events of mouse movement, and does not realize the processing of middle mouse button scrolling and left and right mouse buttons. If necessary, you can also add code to the mouse event handler.

The processing functions are as follows:

EFI_STATUS HandlerMouse(EFI_SIMPLE_POINTER_STATE *State)
{
  INT32 i,j;
  i=(INT32)mouse_xres;
  j=(INT32)mouse_yres;
  i += ((State->RelativeMovementX<<MOUSE_SPEED) >> mouse_xScale);
  if (i < 0)    i = 0;  //The mouse position does not exceed the screen
  if (i > SY_SCREEN_WIDTH - 1)    i = SY_SCREEN_WIDTH - 1;
  j += ((State->RelativeMovementY<<MOUSE_SPEED) >> mouse_yScale);
  if (j < 0)     j = 0;
  if (j > SY_SCREEN_HEIGHT - 1)    j = SY_SCREEN_HEIGHT - 1;    
  putMouseArrow(i, j);  //Draw mouse pattern
}

2.3 keyboard event handling

UEFI provides two ways to access the keyboard. EFI is used in the example project MyGuiFrame_ SIMPLE_ TEXT_ INPUT_ Protocol to handle keyboard keys. If you need to handle key combinations or hotkeys, you must use EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.

The function HandlerGUI() that handles GUI events handles keyboard events. When handling keyboard events, the called function is HandlerKeyboard(), and the implementation code is as follows:

EFI_STATUS HandlerKeyboard(EFI_INPUT_KEY *key)
{
  UINT8 *s_text = "Please Input:";  
  draw_string(s_text,100,100,&MyFontArray,&(gColorTable[WHITE]));//character string 
  rectblock(240,100,270,130,&(gColorTable[DEEPBLUE]));//Clear last display with background color
  draw_single_char((UINT32)key->UnicodeChar, //Display key characters
240,100,                //Display location
&MyFontArray,          //Font array
&(gColorTable[RED]));//gules
  return EFI_SUCCESS;   
}

The prepared keyboard processing function is relatively simple. It will clear the position to be displayed with the background color and display the key characters in red font. The currently prepared example can only handle character numeric keys. EFI must be used for the processing of control keys and switching status keys_ SIMPLE_ TEXT_ INPUT_ EX_ Protocol.

3 code migration

The migration of the code is relatively simple. Put the font in MyGuiFrame c,Font.h,Mouse.c,Mouse.h,MyGUI.c,MyGUI.h,Pictures.c and pictures H copy to the frame code folder of Option ROM. Other supporting documents have been included in the original framework.

The example in this article is called YIE1GUI, and there is still some work to be done.

3.1 removing unnecessary codes

In the MyGuiFrame example, a relatively large BMP file is shown, which will cause the generated file to exceed 32K and must be removed. In fact, in the process of copying, the main file guipic C and guipic H is not copied to the framework code folder.

Pictures The functions provided in C are only used when drawing the mouse, and only the display function of pcx is used. Therefore, as long as the four functions putPCX256() and putpcx256 related to pcx display are retained_ Fast (), decompressPCX256(), and decompressPCX256_special() is OK. All other functions and related data structures can be commented out.

3.2 add exit mechanism

Rule 4 is that there must always be exit means during programming, which is prepared to prevent failure to exit Option ROM. Add exit mechanism in HelloMyROM() and implement GUI main program:

VOID HelloMyROM(VOID)
{
  UINT64 flag;
  EFI_INPUT_KEY key={0,0};

  gST->ConOut->OutputString(gST->ConOut,L"YIE1GUI: Press key 1 to continue,key 2 to exit...\n\r");
  while(key.ScanCode!=0x17)
  {
    GetKey(&key);
    if(key.UnicodeChar == 0x31)   
      break;
    if(key.UnicodeChar == 0x32)  
      return; 
  }
  flag = InintGloabalProtocols( GRAPHICS_OUTPUT | SIMPLE_POINTER);
  if(flag)
  {
    Print(L"Init Procotols: flag=%x\n",flag);
    WaitKey();
  }
  else
  {
    SwitchGraphicsMode(TRUE);
    SetBKG(&(gColorTable[DEEPBLUE]));
  // ShowBMP24True(L"mygui.bmp",400,100);
  // ShowMyGuiPic(400,100);
    InitGUI();
    HanlderGUI();  //Added ESC key exit mechanism
    SetMyMode(OldGraphicsMode);
    SwitchGraphicsMode(FALSE);
  }
 }

In order to prevent the Option ROM from falling into an endless loop, or because the UEFI Protocol used in the operation of the Option ROM cannot operate normally, an exit mechanism is added. When loading, press' 1 'to continue running, and press' 2' to exit Option ROM.

3.3 modification of INF documents

Add the file to be compiled to the [Sources.common] Section of the INF file and modify the FILE_GUID of the GUID.

So far, the migration of the code has been completed.

4 compilation and testing

The compilation command is as follows:

C:\UEFIWorkspace>build -t VS2015x86 -p RobinPkg\RobinPkg.dsc \
-m RobinPkg\Drivers\YIE1GS\YIE1GS.inf -a X64

Test on the actual machine according to the method described earlier. However, on the machine I tested, after Option ROM was swiped into YIE001, the Event mechanism could not be supported during loading, resulting in failure to run.

The following is the effect obtained by testing ROM under UEFI Shell:

Figure 1 test YIE1GUI

The migration of YIE1GUI has been completed. Other UEFI programs in the series of blogs can also be transplanted in the same way.

By the end of this article, we have introduced how to program Option ROM on YIE001. The chip of CH366 is not complex. At present, it is also widely used in the fields of restore card, data protection card and so on.

However, at present, there are few PCIe products developed under UEFI. I want to do some work and exploration in this subdivided field, so the development board YIE001 was born.

Of course, interested technologies can also be developed with other PCIe chips. As far as I know, many manufacturers are also developing video card ROM and network card Rom. the series contents of YIE001 introduced now are also applicable. I hope you have a good time in the world of UEFI!

Gitee address: https://gitee.com/luobing4365/uefi-exolorer
The ROM files used for the project are located under: / 80 YIE1GUI

Tags: uefi pci-e bios

Posted by yeshuawatso on Tue, 19 Apr 2022 02:08:23 +0930