UEFI开发探索19 – 使用HII显示汉字4

已经实现了UEFI Shell下使用SimpleFont和Font,在Graphics模式下来实现就相对容易很多了。

我大部分的工作都是在整理文件,以及按照之前的代码结构,专为Hii构建了源代码文件,把一些细节封装起来,以备后用。

图1 整理好的源代码

可以讲解的地方不多,主要是在开发中遇到的一些问题:

继续阅读“UEFI开发探索19 – 使用HII显示汉字4”

39 total views, no views today

UEFI开发探索18 – 使用HII显示汉字3

本篇博客的关键字:Font。

今天准备把UEFI另外一种字体Font的方方面面研究一下,仍旧是以代码移植为主,间以解决自己提的几个问题。

1 Text模式和Graphics模式

实验之前,我想谈一下Text模式和Graphics模式。UEFI spec中,对于Text模式和Graphics模式谈的比较少。我一直很疑惑,spec中的Text模式和Graphics模式是不是我所理解的。

继续阅读“UEFI开发探索18 – 使用HII显示汉字3”

72 total views, 1 views today

UEFI开发探索17 – 使用HII显示汉字2

本篇博客的关键字:SimpleFont。

我始终在思考如何在UEFI Shell下显示汉字。上一篇中,参考书中的例子,基本了解了字符串资源是怎么组织的。当在TestString函数中,把参数Language改为”zh-Hans”,什么也没有显示。

看来还是缺少相应的字库。

UEFI下提供了SimpleFont和Font字体,前一个相对简单些,我先拿这个开刀。我参考的例子是《UEFI原理与编程》的\GUIbasics\font\SimpleFont,这个例子直接编译没有成功。我也没有去找原因,还是老办法,把它的例程移植到我自己的程序中来。

1 SimpleFont格式

SimpleFont有两种字体格式,窄字符和宽字符,在书中描述得很清楚。TianoCore的模拟环境中,也使用了SimpleFont的字库。

继续阅读“UEFI开发探索17 – 使用HII显示汉字2”

69 total views, no views today

UEFI开发探索16 – 使用HII显示汉字1

上一次博客中,我使用自己的方法显示汉字,其核心思想不外乎利用实现的画点函数,将汉字一个像素一个像素地画出来。

很明显,这种方法只能在图形模式下实现。如果想在字符模式下显示(比如UEFI Shell),则无能无力了。虽然目前商用的Option Rom不可能用到字符模式,奈何寻根究底的程序员本性,驱使着我把UEFI本身提供的Human Interface Infrastructure机制搞明白。

于是开始了我这几天的探索之旅。

所有的探索都是从问题开始,对HII,我提的问题如下:

  1. 如何组织汉字库(其他语言也一样,怎么存储字库?);
  2. 是否能在UEFI Shell下显示汉字,如何实现?
  3. 图形模式下如何显示汉字?
继续阅读“UEFI开发探索16 – 使用HII显示汉字1”

40 total views, no views today

UEFI开发探索15 – 图形模式下文字显示

UEFI中提供了HII(Human Interface Infrastructure)用来处理图形界面的文字显示,这一块我一直没有去仔细研究。到目前为止,显示汉字和字符,我都没有采用这种方法。

比如之前博客中演示了测试样卡的界面,图形中用到了各种英文和汉字,都是采用我自己的方法来实现的。

HII的思考方式不大直接,当时我面临着要在几周内完成UEFI Option ROM的开发,需要克服的困难太多,图形模式下的汉字和英文字符的显示,我采用了Foxdisk中的显示方法。

具体来说,在前面的博客中,已经实现了画点函数(putpixel)函数,那么把所有汉字及英文字符看做一个个的字模,画出来就行了。所有的核心思想皆源于此。

继续阅读“UEFI开发探索15 – 图形模式下文字显示”

116 total views, 1 views today

UEFI开发探索14 – 访问PCI/PCI-E设备2

(关于PCI访问,其中一些内容来自网上,找不到出处了)

PCI规范使用从0CF8H~0CFFH 这8个I/O地址来访问所有设备的PCI配置空间。这8个字节实际上构成了两个32位寄存器:0CF8H寄存器叫做“配置地址寄存器”;0CFCH叫做“配置数据寄存器”。

当要访问配置空间的寄存器时,先向地址寄存器写上目标地址,然后就可以从数据寄存器中读写数据了。

PCI配置空间对应于一个PCI逻辑设备,所以要访问一个配置空间的某个寄存器,必须要指定:PCI总线号、PCI设备号、PCI设备功能号和寄存器号。配置地址寄存器的格式如下:

继续阅读“UEFI开发探索14 – 访问PCI/PCI-E设备2”

141 total views, no views today

UEFI开发探索13 – 访问PCI/PCI-E设备1

我所用的测试卡是PCI-E设备,公司商用的产品也是PCI-E设备。所以,我很早就“被迫”去读那些PCI spec。

从软件工程师的角度,我觉得只要解决几个问题就行了,其余的细节不妨碍编程。

1)      PCI/PCI-E设备是如何定位的,也即程序如何找到设备;
2)      系统把它认作什么设备;
3)      如何访问设备的内部寄存器(一般要去读所使用的PCI-E芯片的资料);
4)      商用化的产品,需要考虑设备对ACPI的各种电源事件的处理。

继续阅读“UEFI开发探索13 – 访问PCI/PCI-E设备1”

100 total views, 1 views today

UEFI开发探索12 – Oprom测试板

今天拿到了测试板,可以把UEFI Oprom写到硬件里面去了。手有点痒,想写一个程序来试试。

测试用的板子非常简单,去除了所有实际的硬件控制元器件,只留下了WCH366和一个128K的ROM。不过按照沁恒电子的资料,WCH366只支持64K的寻址,而且还不能同时寻址,意味着我们只有32K的空间可以写代码。

做了十个,足够我折腾很长时间了。

图1 测试用的小板卡
继续阅读“UEFI开发探索12 – Oprom测试板”

64 total views, no views today

UEFI开发探索11 – 鼠标前传

这不是写鼠标的历史,而是记录在很久以前,在Legacy BIOS下,我写鼠标驱动(BIOS/DOS下运行)的过程。

我对底层编写程序,从参加工作的时候就非常着迷。当时接手隔离卡5.0的开发维护,主体产品已经完成,我一直思考:怎么才能让产品和别家的不同呢?

介绍下背景知识:隔离卡V5.0是公司第一款采用PCI Oprom开发的产品,插上就可以出界面。省去了用户安装软件的过程,一推出就大受欢迎。我们采用的是沁恒电子的WCH365,代码也参考他们的DEMO开发的。很快,对手使用同样的芯片,有了同样的方案。

就是在这种情况下,我希望找到新的竞争点。突然想到,市场上所有的PCI Option ROM上的界面,都是支持键盘的,没有支持鼠标的。这不就是一个切入点吗?如图,这是当时的隔离卡。我工作的笔记本没带回来,图是从网上找到的,这么多年,没想到还能找到。

图1 易思克隔离卡v5.0

有了想法,执行起来也不容易。

问题1: 鼠标肯定是在图形模式下运行的,怎么无缝的将鼠标显示在目前的界面?
问题2: 针对鼠标的驱动代码量不能大,ROM只有32K,现在出货的产品已经有21.5K,留给鼠标驱动的就没有多少空间,必须控制代码量;
问题3: 我知道DOS下有int33h可以控制鼠标,也有大量的例子可以参考。可惜我们是在BIOS上运行的,无法调用;

继续阅读“UEFI开发探索11 – 鼠标前传”

87 total views, 1 views today

UEFI开发探索10 – 再论键盘

突然想起一句诗:戍客望边色,思归多苦颜。也许是天气原因,也许是出差,心情总是不好。

上海的天空,灰蒙蒙的。一眼望去,都是淡墨色的乌云,不沉重,也透不过阳光。窗外的风很小,茂盛的树叶一动不动。除了传来的汽车声音,几乎要怀疑时间停止了一样。

没有阳光的天气,让人心情比较压抑。

继续阅读“UEFI开发探索10 – 再论键盘”

78 total views, 1 views today

UEFI开发探索09 – 图形显示02

上次对UEFI的图形模式有了一定的了解,根据得到的信息,我准备用1024×768的分辨率来运行程序。

这个分辨率我比较熟悉,以前的代码(legacy bios下)可以复用。在Vesa标准中,有多个模式是这个分辨率的(我最常用的是105h)。如图:

图1 VESA graphics

那么UEFI的这个分辨率对应的是哪个模式呢(UEFI 下的模式索引值为3)?虽然都是从EDID中读出来的,不过经过了UEFI 的重组,我也搞不清到底是对应哪个。从blt的操作方式来看,可能是118h;不过似乎其他的模式也能类似操作。

算了,不纠结了,什么时候去跟下代码就知道了。

继续阅读“UEFI开发探索09 – 图形显示02”

64 total views, 1 views today

UEFI开发探索08 – PE/COFF

前几天有人问起我,对UEFI的格式文件的理解。

嗯,我基本上快把PE格式忘光光了,那是很多年前,搞反汇编,混看雪学院时搞的事情。当时花了几个月,专门学习软件加密、加壳、扰乱反汇编等等。然后,又花了几周,破解了几个dll,扔给工程师去用,就再也没有接触过了。

闲言少叙。既然忘记了,就花点时间去回忆一下吧。上午的会议开完,下午有两个小时空档,找找以前的日志和资料。

继续阅读“UEFI开发探索08 – PE/COFF”

102 total views, 3 views today

UEFI开发探索07 – 关于SMBUS的开发故事

这篇博客曾经发表在高端调试的论坛上,我把它转移到这里来了。UEFI访问SMBUS设备,是我计划中要写的,这篇就作为其前言吧,其中没有任何与UEFI相关的内容。

当时我已经开发完了C850F320上的smbus访问代码(作为smbus device)、Legacy BIOS下的smbus访问代码(在dos下调试,运行于OptionRom上),期望在windows上开发一个驱动,能通过smbus直接访问C850F320。这能让目前产品的价格降低20元,以当时的出货量,一年的成本可以节省40w,很可观的。

我把这篇博客拷贝过来了,绝不是因为今天上午要开会,没时间写了。说不是就不是!

以下为原文:

继续阅读“UEFI开发探索07 – 关于SMBUS的开发故事”

141 total views, 1 views today

光伏云项目杂记02 – 构建Ringbuff(环形缓冲)1

在做这个项目的时候,遇到一个问题。我们使用的STMF103C8T6,资源很可怜,看看:

图1 STM32F103C8T6的参数

72M的频率,内存只有20K。而这个芯片需要做的事情:

1 3个串口的收发;
2 3个灯的控制,让用户通过灯的闪烁判断处于什么状态,方便维护;
3 GPRS模块的协议管理;
4 与逆变器端的协议管理;
5 看门狗的任务处理;
6  服务器端协议的处理,包含应用端口和配置端口;

以FreeRTOS为架构,估计用了近20个任务来完成这些工作。每个任务给的堆栈是0.5K,加上串口需要的缓冲区,一番操作下来,内存基本用光光。一起开发的兄弟,暂且称为烟枪吧(抽烟很快,1分钟一根,当得起这个称呼)。每天嚷嚷,说内存严重不够用,不能让客户再提新的需求了。虽然通过map文件计算了每个任务所用的栈空间,尽可能不浪费。不过再改的话,程序就直接溢出了,问题出在哪都不知道。

我很同意他的看法,也很同情我们的处境。可是,客户又不是我家的,他想提要求,我又控制不住。何况有些要求还是很中肯的,咱们都是讲道理的,对吧?

那怎么办?

分析源代码,我盯上了串口处理的这段代码。三个串口,除去串口接收发送所需要建立的任务外,每个串口还用了256字节的缓冲区。另外,程序写得耦合性比较差,估计换个芯片,所有代码都得重写。

程序逻辑是这样的:

  1. 将缓冲区分为两段,A段128字节,B段128字节;
  2. 串口接收启用DMA传输,不占用CPU资源;
  3. 当触发串口接收DMA中断,中断处理程序将缓冲区指向A段,接收数据;
  4. 接收完毕后缓冲区指向B段;
  5. 有一个任务专门监听,发现有数据立即取走;
  6. 新的数据来了,DMA接收中断处理程序用B段缓冲区取走数据,收完后缓冲区指针再指向A段。

也就是说,当监听任务在处理数据的时候,DMA接收中断使用了另外一段缓冲区,大家互不干涉(当然程序中也利用了FreeRTOS的互斥量来实现)。

这样实现其实没有太大问题,因为精心计算了串口和DMA的处理时间。接收串口的数据越长,越不会出现问题。

问题就出在小数据上。如果串口接收大量的小数据,频繁的触发中断,CPU就有可能丢失数据了。(实际运行中没有出现过,连续发送1个字节的情况,在客户环境中可认为概率是0)

烟枪和我商量了一段时间,我们决定使用ringbuffer(环形缓冲)来实现。他把这个任务轻飘飘的交给我了,调他的板子去了。

没办法,开始干活吧。 Ringbuffer的基本原理,我大概了解。维基百科中也有说明:https://en.wikipedia.org/wiki/Circular_buffer

A 24-byte keyboard circular buffer. When the write pointer is about to reach the read pointer – because the microprocessor is not responding, the buffer will stop recording keystrokes and – in some computers – a beep will be played.

我能用的资源有限。必须实现原有的串口接收,不能丢数据;同时还有提供尽可能简单的接口,供应用层的函数调用。

因此,我选择使用Contiki中的代码,用它的核心思想来构建这个架构。当时估计错误,我不觉得能有多难,本以为一周左右能搞定。没想到对芯片的DMA以及串口不那么熟悉,整整花了我三周时间。

这是一段痛并快乐的回忆。

68 total views, no views today

UEFI开发探索06 – 图形显示01

到了我最喜欢的环节了,图形显示!

我曾经写过不少关于图形显示的博客和论文,特别是在Legacy BIOS以及嵌入式设备中的显示。PC的显示一直都遵循着VESA的标准,在底层的访问还是比较一致。虽然在多年的开发中,也在一些主板上出现过奇怪的现象(一次而已。Award某款主板,设置显示模式的时候,花屏。在调用设置显示模式的函数前,多压几次堆栈,问题又消失了。)。但当年写的核心显示代码,运行了近10年了,也没出现过显示的问题。

这是我曾翻烂过的参考书:

图1 参考书

还有这些…

图2 参考书

以及《最新VESA SVGA图形图像编程秘技》 李军著、《C语言游戏编程从入门到精通》,还有图像格式,主要是BMP、PCX和jpeg。哦,还有一本雷军(没错,我就是当年用过这本书,才成为米粉的)和求伯君的《深入DOS编程》。

写得最扎实的是《IBM PC的原理及应用》以及《PC技术内幕》,想了解底层显示原理的可以参考一下。虽然我觉得这些知识有点过时了,但对理解还是有帮助的。

继续阅读“UEFI开发探索06 – 图形显示01”

129 total views, 4 views today

UEFI开发探索05 – 搭环境遇到了问题

这两天妻子去阜宁,孩子没有带过去。我只能在陪孩子之外,腾出一点点时间,来搭建UDK2017/UDK2018的编译环境。

大部分的时间都在装VS,试了两个版本,VS2013和VS2015。我不知道是不是我的版本有问题,总是不成功。Ubuntu16.04的也没有安装成功,让人颇为恼火。总计来回折腾了12个虚拟机,真是不甘心。

下周开始又没有太多时间了,几个案子都在催着完成,有大量的工作要去做。两个专利也还没写,前期的资料都还没收集完。思来想去,我仍旧以UDK2010来编译这些代码吧。主要的目的是熟悉这些API和UEFI的架构,我目前没有开发BIOS,太细节的暂时不必理会。

插一句,为了方便调试,我请同事做了一些带有PCI-E扩展ROM的卡,主芯片是CH366,下周应该可以到我手上了。对于进入操作系统之前,可以跑自己的程序,我一直很热衷:总想脱离操作系统做点什么坏事。→_→

比如针对操作系统核心的几个文件ntldr.dll,gdi32.dll等,使用Oprom对其认证,防止篡改。或者和杀毒软件配合,进入OS前做些事情。整个硬盘都可以控制,可以预先做很多动作。

又扯远了,回到搭建编译环境的事情吧。

我主要使用Vmware搭建虚拟机,开发用的操作系统为win10。中间的各种小问题就不说了,基本上都解决了。主要是两个问题,没有找到解决办法。

1. VS2013+UDK2017,VS2013全部安装,WDK8.0和WDK8.1的目录都有。编译Nt32Pkg无法通过。如图1。

图1 UDK2017+VS2013,编译NT32Pkg报错

2. VS2015+UDK2018,Nt32Pkg编译通过,AppPkg编译不通过。本系列Blog中的“UEFI开发探索03-环境搭建2”曾经描述过安装过程。编译AppPkg的报错如下:

图2 UDK2018+VS2015 编译AppPkg报错

这段时间以把程序编译运行为主,就用UDK2010,尽快把博客写完。和张佩去年就约定要把Foxdisk和UEFI的开发记录下来,一直到现在还没搞定,甚是惭愧。

搭建环境的问题,留待日后吧,看是否能凑些边角料的时间来找找原因。O__O

如果哪位朋友知道怎么回事,也望不吝赐教,感激不尽。:)

82 total views, no views today