Showing posts with label Design Pattern. Show all posts
Showing posts with label Design Pattern. Show all posts

Wednesday, June 17, 2015

Make Your Code Portable

The following are principles to make your code portable.

1) Use C instead of C++.

If you want your library more portable, please use C instead of C++.

2) Use C standard library.

Because EDK II supports C standard library, we just use it.

Please refer Use C Library in EDK II UEFI Driver

3) As far as possible, allocate memory space for a returned parameter before calling a public function.

For example,

EFI_STATUS
CompressData (
  IN UINT8 *Buffer,
  IN UINTN BufferSize,
  OUT UINT8 **Output,
  OUT UINTN *OutputSize
  );

This Compress function allocates memory space for the returned Output. The problem is that the memory management mechanisms are different in environments. In UEFI DXE environment, gBS->AllocatePool() supports the memory space allocation. In SMM mode, UEFI provides SmmAllocatePool(). In Windows KMDF, we should use WdfMemoryCreate to allocate memory space.

Therefore please rework the function as below otherwise we need to create many stubs to wrap the memory management functions for different environments.

EFI_STATUS
GetCompressedDataSize (
  IN UINT8 *Buffer,
  IN UINTN BufferSize,
  OUT UINTN *OutputSize
  );

EFI_STATUS
CompressData (
  IN UINT8 *Buffer,
  IN UINTN BufferSize,
  OUT UINT8 *Output,
  IN UINTN OutputSize
  );

4) The sizes of fields in C struct must be determined.

Don't use UINTN or ulong, the sizes are undetermined, in your struct. If you define struct in UEFI environment, please use UINT8, UINT16, UINT32, CHAR8, CHAR16 of which sizes are always same in IA32 and X64.

-Count

Saturday, May 30, 2015

Use Python to Explain Adapter of Design Pattern

The Adapter is described in the Design Pattern book. Please refer the book for the details. A better way to learn Design Pattern is to program it by yourself. Python is a good language because it supports class and is easy to program than C++. That is why I select it to practice Design Pattern.

This page uses Python to implement an Adapter that displays a directory tree.

TreeDisplay is an abstract class that has two abstract methods GetChildren() and CreateGraphicNode(). The sample uses raise in both abstract methods to notify a programmer that the both are abstract that must be implemented in a derived class.




















DirectoryTreeDisplay1 is an Adapter that adapts Python OS package (Adaptee). GetChildren() uses Python OS package to get directory tree. CreateGraphicNode() transforms directory tree to readable text.














Test1() is a test function that tests DirectoryTreeDisplay1 ()











Below is a results after running the Python program in MacBook.
$ python ./DesignPattern/Adapter/TreeDisplay.py


The style of the directory tree is not good. A new Adapter, DirectoryTreeDisplay2, refines the style.















Test2() tests the new Adapter.










The better style of the directory tree displays as below after running the Python program.



























The below class diagram summarizes the implementation.


-Count

Monday, October 13, 2014

Circular Dependency

When I used the EDKII Package, I found that the package is similar to the UML package. We know that we should avoid the circular dependency in software design although the circular dependency always happens in natural domain.

Circular dependency is one of AntiPatterns but we cannot consider it as bad. What is benefit of it? When we want to public our source code of package that depends on a framework package (e.g.,  MdeModulePkg in EDKII.), if we don't want that our ideas in source code are easily stolen by competitors, we can modify the framework package to depend on our package to make circular dependency. Therefore the more circular dependencies we build, the more ideas we protect.

-Count



Monday, September 1, 2014

The Design Pattern of UEFI Report Status Code

Observer is a kind of design pattern that is described in the book, Design Pattern - Elements of Reusable Object-Oriented Software, 1994. I recommend the book as a bible.

This blog page describes that the design patterns are not only used in the implementation with Object Oriented Program (e.g., C++, JAVA), but also used in the implementation (e.g., UEFI) with non OOP (e.g., C). Mostly EDKII are implemented in C language. We can find there are many Observer patterns in it. ReportStatusCode is an example.



If you have the book on your hand, you can compare the package diagram of the blog page with the structure diagram in Observer chapter of the book.

  • The ReportStatusCodeRouterRuntimeDxe.inf  is corresponding to the Subject object.
  • The FirmwarePerformanceDxe.inf and StatusCodeHandlerRuntimeDxe.inf are corresponding to the Observer objects.
  • The Register () is corresponding to the Subject.Attach()
  • The Unregister () is corresponding to the Subject.Detach()
  • The ReportStatusCode() is corresponding to the Subject.Notify()


In OOP implementation, the Notify() calls all Observer->Update() to update all registered Observer objects.
Notify ()
{
  for o in Observers {
    o->Update()
  }
}

But for non-OOP implementation, ReportStatusCode(), how does it work? Below is the protocol definition of EFI_RSC_HANDLER_PROTOCOL.

typedef struct {
  EFI_RSC_HANDLER_REGISTER Register;
  EFI_RSC_HANDLER_UNREGISTER Unregister;
} EFI_RSC_HANDLER_PROTOCOL;

Let's focus on Register() in which we only be interested. For Unregister(), it seems that it is seldom used.

typedef
EFI_STATUS
(EFIAPI *EFI_RSC_HANDLER_REGISTER)(
  IN EFI_RSC_HANDLER_CALLBACK   Callback,
  IN EFI_TPL                    Tpl
  )
;

The most important parameter of the Register() is Callback. Below is the prototype of the Callback, EFI_RSC_HANDLER_CALLBACK.

typedef
EFI_STATUS
(EFIAPI *EFI_RSC_HANDLER_CALLBACK)(
  IN EFI_STATUS_CODE_TYPE   CodeType,
  IN EFI_STATUS_CODE_VALUE  Value,
  IN UINT32                 Instance,
  IN EFI_GUID               *CallerId,
  IN EFI_STATUS_CODE_DATA   *Data
  );

Below is the prototype of the EFI_STATUS_CODE_PROTOCOL.ReportStatusCode().

typedef
EFI_STATUS 
(EFIAPI *EFI_REPORT_STATUS_CODE) (
  IN EFI_STATUS_CODE_TYPE     Type,
  IN EFI_STATUS_CODE_VALUE    Value,
  IN UINT32                   Instance,
  IN EFI_GUID                 *CallerId  OPTIONAL,
  IN EFI_STATUS_CODE_DATA     *Data      OPTIONAL
  )

We found that the prototype of Register() and ReportStatusCode() are same. Therefore I guess that the implementation of the ReportStatusCode() should be as follows. Forgive me that I use python-style pseudo code to explain it.

ReportStatusCode (params):
  for CallBack in mCallBackList:
    CallBack (params)  

Is pseudo code really true? You can trace the EDKII source code by yourself to verify if my assumption is true. This page just describes that there are many design patterns in EDK and EDKII. Furthermore, the ReportStatusCodeRouterRuntimeDxe.inf should be a design pattern of Singleton. What is Singleton? Please read book or GOOGLE it.