pretty code

2019年7月31日 星期三

UEFI Application - EntryPoint

一般我們在寫 UEFI Application 時,有 3 種方式可以寫,不同方式有不同的 Entry 及套用的 Library,一般來說越下層的 Entry 其檔案 size 也越大,注意這裡指的下層是指呼叫的層級順序,非指底層。

不同的 Entry,其預設的字串編碼也不同,UEFI 預設是使用 Unicode ﹝UINT16﹞,而標準 C 則是使用 ASCII﹝char﹞。

不過,為了 porting 的方便,我大部份都使用 main 型式,反正還是可以呼叫 UEFI 相關函數。

C code Entry UefiMain ShellAppMain main
parameter EFI_HANDLE        ImageHandle,
EFI_SYSTEM_TABLE  *SystemTable
UINTN Argc,
CHAR16 **Argv
int argc,
char *argv[]
include file   #include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
  
[Defines] (INF)
ENTRY_POINT
UefiMain ShellCEntryLib ShellCEntryLib
[Packages] (INF) MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
StdLib/StdLib.dec
[LibraryClasses] (INF) UefiApplicationEntryPoint
UefiLib
ShellCEntryLib
UefiLib
ShellCEntryLib
UefiLib
LibC

為了避免不必要的誤解,我都習慣不將不需要的東西放入專案,這樣一來,Code 看起來才會賞心悅目。

2019年7月23日 星期二

或躍在淵

夏研先生在其著作《陪你飛一程:科技老鳥30年職場真心話》第四章或躍在淵中提到底下這一段話:

無論是在一個新創公司,或是一個五百大企業,市場在變、局勢在變、周圍的情況也在變化。埋頭苦幹的時代已經過去,眼觀四面、耳聽八方才是保命之道。

如果有一個優先次序,可以從幾個角度思維:
一、目前所處的是不是正在上升的產業。
二、工作的公司是不是對的公司。
三、團隊是不是一個對的團隊。
四、自己的心態是不是正確。

我想答案已經呼之欲出了...

2019年7月22日 星期一

memset in UEFI

最近常常操作 unsigned long long 的 2 維陣列,故突發奇想,是否可以使用 memset 來 init 1 個大於 1byte 且非 0 的值呢?

上面是 C11 規格書中提到的 memset 定義,我們可以看到第 2 個參數雖然接受的是 1 個 int,但最後會轉成 1 個 unsigned char,故看起來應該是不行。

至於 UEFI 中的 memset 實作是在 Stdlib\LibC\String\Misc.c 中,細節如下,看起來應該是跟 Stanard C 一樣,會被轉成 unsigned char。

#if !((defined(MDE_CPU_ARM) || defined(MDE_CPU_AARCH64)) && defined(__GNUC__))
/** The memset function copies the value of c (converted to an unsigned char)
    into each of the first n characters of the object pointed to by s.

    @return   The memset function returns the value of s.
**/
void *
memset(void *s, int c, size_t n)
{
  return SetMem( s, (UINTN)n, (UINT8)c);
}
#endif

不過,UEFI 另外有 InternalMemSetMem64 的函數,其實作位於 MdePkg\Library\BaseMemoryLib\MemLibGeneric.c 中,看來我們可以使用這個函數。

/**
  Fills a target buffer with a 64-bit value, and returns the target buffer.

  @param  Buffer  The pointer to the target buffer to fill.
  @param  Length  The count of 64-bit value to fill.
  @param  Value   The value with which to fill Length bytes of Buffer.

  @return Buffer

**/
VOID *
EFIAPI
InternalMemSetMem64 (
  OUT     VOID                      *Buffer,
  IN      UINTN                     Length,
  IN      UINT64                    Value
  )
{
  for (; Length != 0; Length--) {
    ((UINT64*)Buffer)[Length - 1] = Value;
  }
  return Buffer;
}

2019年7月19日 星期五

LShiftU64 釋疑

原本以為 LShiftU64 是我們自己寫的函數,後來才發現是 Library\BaseLib 裡面的函數,看了一下說明,跟直接使用 Standard C 操作似乎並沒兩樣?

我唯一能想到的合理解釋就是為了方便 porting,例如為了 32bit 的執行檔,只是不知道這樣是否真有意義?反正我對這行業的 Code 早已經見怪不怪了XD


#include <stdio.h>
#include <Library/BaseLib.h>

int main(void)
{
    unsigned long long a = 0x0000000000000001;
    
    UINT64 b = LShiftU64(a, 2);
    UINT64 c = a << 2;
    
    printf("UEFI 0x%016llX, 0x%016llX \n", a, b);
    printf("StdC 0x%016llX, 0x%016llX \n", a, c);
    
    return 0;
}
執行結果

UEFI 0x0000000000000001, 0x0000000000000004 
StdC 0x0000000000000001, 0x0000000000000004 


後記
似乎真的是跟 porting 有關,在網路上找到 2 篇相關文章。

[edk2] [Patch] MdeModulePkg: use LShiftU64() instead of "<<" to avoid IA32 build error.
Fix ScsiLib build break by << operator, which is replaced by LShiftU64 of BaseLib.

2019年7月18日 星期四

我的 10 吋電子書閱讀器在哪裡

自從 Onyx Boox Note Lite 掛掉後,都不能看 PDF 的書籍。

原本打算直接下訂 mooInk Pro,沒想到還是得在特定的時間上網搶購,真不知道之前登記的意義在哪裡?剛好最近又很忙,搶購當天早上 1 點才睡,4 點就起床,7 點出頭就在辦公室寫 Code 了,想當然爾根本就忘了有這件事。

我的下一台 10 吋電子書閱讀器在哪裡?

2019年7月12日 星期五

VC 編譯警告取消方式

UEFI 下存取記憶體時,有時會有 C4305 和 C4306 的編譯警告,但是那個 address 就是我們要的,暫時解法可以使用 marco 來取消此警告。

#pragma warning(push)
#pragma warning(disable:4305)
#pragma warning(disable:4306)

//your code.

#pragma warning(pop)

另外一種方式是使用 command line 參數
/wd4305 /wd4306

UEFI Boot Variable 取值注意事項

困擾我一個星期的問題終於解決了!

一般來說,我們在取 Boot Variable 時,會先取得 BootOrder 這個變數的內容,因為裡面的 1 個開機項目是 2 Byte,故我們會把取到的 BootOrder size 除以 2 好方便我們取得所有項目個數,之後就可以用 for 迴圈依序取得 Boot Variable。

好死不死的,我們系統的的 BootOrder 是長底下這樣,故我先取 Boot0001 當然會取不到,害我一直往 EDK1/EDK2 的方向去找問題。另外,變數名稱前面不需要加上 "Efi:"。


sample code 如下:

    orderValue = mGetVariable(L"BootOrder", &gEfiGlobalVariableGuid, &size);
    if (orderValue == NULL) {
        printf("Can't get BootOrder Variable \n");
        return ERROR;
    }

    varCount = size / 2;
    for (i = 0; i < varCount; i++) {
        ptr = (char*)orderValue;
        num = (UINT16*)(ptr + i * 2);
        
        UnicodeSPrint(bootString, sizeof(bootString), L"Boot%04x", *num);
        
        value = mGetVariable(bootString, &gEfiGlobalVariableGuid, &size);
        if (value == NULL) {
            printf("Can't get Boot%04X Variable \n", i);
            return ERROR;
        }
        
        // 底下省略
    }

UEFI Memory Map and BIOS E820 Table

趁著手上的事暫時告一段落的空檔,把幾天前 Google 到的資料整理一下,免得之後還要再查一次。

RU Tool 有一個可以看 BIOS E820 Table 的功能,E820 名稱是從指令 INT15h, AX=E820h 來的,因為我們對 AX 設值 E820,故命名為 E820 Table。Legacy BIOS 會把這個 Table 建好,OS 就知道那些 RAM 是可以用的。

來到了 UEFI 的時代,取而代之的是 UEFI Memory Map,我們可以透過 BootServiceGetMemoryMap 函數來取得相關資訊,雖然我沒試過,但應該會等於 Shell memmap 指令的結果。

另外,從網路上查到的資料,Linux 似乎傾向使用 E820 Table,故會將 UEFI Memory Map 的資料轉換後填寫到原 E820 Structure。

有興趣的可以看此篇文章


2020/06/03 更新

最近在看 dmesg log 時,無意間看到 E820 資訊,拍張照片記錄一下。

2019年7月10日 星期三

UEFI IndexVar in for loop

英文果然不是我的菜,一直卡在 IndexVar 怎麼命名都不對的情況!

查了一下 Code,發現 Code 只允許一個字元!


靜一下心,再把文字說明看一下,原來 IndexVar 只允許一個字元,真不知道是那個人想出來的,都不能使用有意義的變數名稱。

If after expansion no such files are found, the literal string itself is kept. Indexvar is any alphabet character from ‘a’ to ‘z’ or ‘A’ to ‘Z’, and they are case sensitive. It should not be a digit (0-9) because %digit will be interpreted as a positional argument on the command line that launches the script. The namespace for index variables is separate from that for environment variables, so if indexvar has the same name as an existing environment variable, the environment variable will remain unchanged by the for loop.

2019年7月9日 星期二

Onyx Boox Note Lite 拆機照片

無意間發現之前拆 Treo 600 買的特殊規格螺絲起子就可以用來拆解 Note Lite。

雖然有了工具,但由於卡榫過多,故需要花費一番力氣,但不用擔心會把卡榫用斷。

把它拆開後,目測倒是看不出來什麼問題,可惜手上沒有三用電表,無法確認電池好壞,拍張照留作紀念,致我失去的 NT$13,400!


Trello 新增卡片小技巧

如果貼上的文字是有換行字元的
Trello 會自動偵測並提示要如何新增卡片




2019年7月4日 星期四

python package 待解疑問

貌似 python package 名稱使用 "-" 會有問題,我還找不到文件說明的地方,但是 PyPI 網站卻允許使用 "-",有點被搞糊塗了,以後再回來找答案。

2019/07/04 更新
在 PEP 8 中有提到命名的規則,如下所述。

Package and Module Names

Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability. Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.

When an extension module written in C or C++ has an accompanying Python module that provides a higher level (e.g. more object oriented) interface, the C/C++ module has a leading underscore (e.g. _socket).


2019/09/17 更新
在 Python bug 討論中看到,確實 "-" 是不合法的,只是不知道還適不適用在 Python 3。

awk 小技巧

這是第 2 次在相關專案中看到一樣的 awk 技巧,感覺還蠻好用的,記錄一下,以備不時之需。

假設我們使用 ls -al 列出所有檔案。

total 100
drwxrwxr-x 15 sw3 sw3  4096  六  17 16:59 .
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:58 ..
-rw-rw-r--  1 sw3 sw3  1472  六  17 16:59 benchmark_readme_template.md
drwxrwxr-x  2 sw3 sw3  4096  六  17 16:59 community
drwxrwxr-x  6 sw3 sw3  4096  六  17 16:59 compliance
-rw-rw-r--  1 sw3 sw3  2359  六  17 16:59 CONTRIBUTING.md
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 data_generation
drwxrwxr-x  8 sw3 sw3  4096  六  17 16:59 .git
-rw-rw-r--  1 sw3 sw3    74  六  17 16:59 .gitignore
-rw-rw-r--  1 sw3 sw3   298  六  17 16:59 .gitmodules
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 image_classification
-rwxrwxr-x  1 sw3 sw3  1133  六  17 16:59 install_cuda_docker.sh
-rw-rw-r--  1 sw3 sw3 11348  六  17 16:59 LICENSE.md
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 object_detection
-rw-rw-r--  1 sw3 sw3  3193  六  17 16:59 README.md
drwxrwxr-x  4 sw3 sw3  4096  六  17 17:36 recommendation
-rw-rw-r--  1 sw3 sw3   771  六  17 16:59 reference_results.md
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 reinforcement
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 rnn_translator
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 sentiment_analysis
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 single_stage_detector
drwxrwxr-x  4 sw3 sw3  4096  六  17 16:59 speech_recognition
drwxrwxr-x  3 sw3 sw3  4096  六  17 16:59 translation
這時我們可以用 awk '{print $9}' 取出檔案名,$0 是原始字串,其他就照順序從 1 開始。

如果想一氣呵成將它產生到另外一個檔案,我們可以把指令一起下完。

ls -al | awk '{print $9}' > tmp.log

2019年7月3日 星期三

Rust 探索之旅 - 函數回傳值

使用 return 就跟平常 C 語言用法一樣。

我們也可以不使用 return,但是傳遞回傳值的那一行不用加分號。

fn main() {
    let s1 = String::from("hello");

    let (s2, len) = calculate_length(s1);

    println!("The length of '{}' is {}.", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
    let n = s.len();
    (s, n)
}

法律小學堂 - 妨害名譽

最近開始看《一不小心就被吉》這本書,感覺蠻有趣的,記錄一下其中的名詞。

妨害名譽可分為公然侮辱及誹謗 2 種,分別在以下條文敘述,簡單來說單純辱罵沒有涉及具體事實評論的就是公然侮辱。

而誹謗之事,如果是涉於私德,即使是真的,也會構成誹謗要件。故甲和乙即使 2 人真的有不可告人之事,意圖散布於眾也是會出事的。

看了這本書,果然是上了一課。


2019年7月2日 星期二

人不親土親

能夠在英文文章中看到熟悉的品牌真的是一件很開心的事!

決定了,下一台就是你了【mooInk Pro】。

mookInk Pro 吸引我的有幾點:
1. 10 吋又只有 240 g。
2. 台灣廠商。
3. 可以看 PDF。
4. 我在讀墨買的書最多。

可能是缺點的:
1. 電池只有 2000 mAh。
2. 還是走 Android,而不是另外開發 Linux Readmoo App。
3. 觸控筆也要充電。

https://goodereader.com/blog/electronic-readers/these-are-all-the-new-ereaders-that-are-coming-out-in-2019


人體 Compiler 果然很難

今天在測試 struct memory dump 時,無意間發現使用 gcc -S 轉出來的組語很不一樣,我只能說再給我 10 年我也不會想到可以這樣寫,組語其實也蠻有趣的XD


2019年7月1日 星期一

不同 OS Shell 常用語法

偶爾會在 Windows、Linux 和 UEFI Shell 下跑來跑去,各個 Shell 的常用語法都不同,乾脆記錄一下,才不用每次都 google。

Windows Linux UEFI
Declare Variable set ABC=XXX  ABC=XXX set ABC XXX
Use Variable echo %ABC% echo $ABC echo %ABC% 
Error Indicator echo %ERRORLEVEL%  echo $? echo %LASTERROR%
The variable scope in other script  global must use EXPORT  ??

實體 Reset 鍵之必要性

不知道有沒有記錯?以前買的 Palm PDA 都有 reset 孔,至少我確定 Treo 600是有的!如果我的 Note Lite 有這個鍵,只要拿迴紋針戳一下,搞不好我的問題都解決了,想要拆開機器,還要去買特殊規格的螺絲起子,一整個怒。

如果可以送修事情就簡單了,問題是我裡面有幾個花錢購買的 PDF,如果被外流要怎麼辦?我實在是對廠商沒什麼信心。

一個實體 reset 鍵花不了多少成本吧?我寧願增加體積及犧牲美觀,也不願意無法 reset CPU,Please give me the fucking reset button.