ubuntu12.04 上搭建 bochs2.3.5 调试环境
在 ubuntu12.04 64 位环境下使用源码编译 bochs2.3.5 带 debug 带 gui 版本。
鱼翔浅底
Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.
1 | $ hexo new "My New Post" |
More info: Writing
1 | $ hexo server |
More info: Server
1 | $ hexo generate |
More info: Generating
1 | $ hexo deploy |
More info: Deployment
Platform Key
Key Exchange Key
合规数据库
禁止数据库
db 及 dbx 存放的是记录以及由某个 KEK 对该记录进行签名的数据,记录可以是:
1. efi 文件的 hash 值
2. efi 文件的签名数据
3. 对 efi 文件进行签名的证书
PK 由平台所有者持有,比如联想
KEK 由 PK 签名
db/dbx 数据进行更新时,bios 需要进行授权验证,验证该更新数据是否是由某个 KEK 进行签名,若验证通过,则将该条记录及其对应的签名数据存入 db/dbx。
MSCApri 以及 UEFICApri 可以对厂商提供的驱动进行签名。
比如某个显卡厂商 Card
使用自己的私钥 (Cardpri) 对自己的驱动进行签名生成 CardSign,(其证书为 CardCert)。
找 UEFICApri 对自己的数据(CardSign、CardCert)进行签名,生成 ((CardSign,UEFICApri_CardSign_Sign )(CardCert,UEFICApri_CardCert_Sign )) 。
调用 bios 接口进行更新,更新数据为 ((CardSign,UEFICApri_CardSign_Sign )(CardCert,UEFICApri_CardCert_Sign ))
bios 中有 UEFICApub 对应的 KEY (UEFIKEKpub)
bios 遍历 KEK,使用 KEK 对 ((CardSign,UEFICApri_CardSign_Sign )(CardCert,UEFICApri_CardCert_Sign ))进行验签
验签通过,将条目 (CardSign,UEFICApri_CardSign_Sign)、(CardCert,UEFICApri_CardCert_Sign)存入 db
按照上述校验流程,显卡厂商也可以不使用自己的私钥对驱动签名,而只是生成一个哈希值。
再使用 UEFICApri 对哈希值进行签名生成 (CardHash, UEFICApri_CardHash_Sign)。
要将该哈希及对应签名信息更新到 db 时,仍然要使用 KEK 验证 UEFICApri_CardHash_Sign。
使用 hash 值的 efi 文件在启动时,只需要验证该 efi 文件的 hash 是否匹配 db/dbx 中的某个 hash。
dbx 内容与 db 中数据格式一致,匹配 dbx 中数据则认为验证失败
市面上已经有大量使用 MSCApri 以及 UEFICApri 签名的 efi。
要加入该体系,只需要,使用 PKpri 对 MSCApub 及 UEFICApub 进行签名,生成对应的两个 KEK: MSKEKpub UEFIKEKpub。
将该两个 KEK 加入 bios , 即可以支持已签名的 efi。
比如 grub
OS Loader 使用 MSCApri 签名,对应的 MSCApub 存储于 db,同时 MSKEKpub 也内置于 bios。
db/dbx 每条记录都是 数据以及使用 KEK 对该数据的签名。
bios 启动时,逐条遍历记录并验证签名。
通过使用分级密钥体系
Sync From: https://github.com/TheBigFish/blog/issues/15
This means that all functions are non-data descriptors which return bound methods when they are invoked from an object.
所有的函数都是一个无数据的描述器。类实例调用函数即触发描述器语法,该描述器在类实例被调用时,返回一个绑定的普通方法。
下面实现了一个纯 python 的描述器 BindFunction, 用来绑定方法 f_normal 到函数 f。
1 | class D: |
类 BindFunction 也可以实现如下:
1 | class BindFunction(object): |
Python’s object oriented features are built upon a function based environment. Using non-data descriptors, the two are merged seamlessly.
Class dictionaries store methods as functions. In a class definition, methods are written using def or lambda, the usual tools for creating functions. Methods only differ from regular functions in that the first argument is reserved for the object instance. By Python convention, the instance reference is called self but may be called this or any other variable name.
To support method calls, functions include the __get__() method for binding methods during attribute access. This means that all functions are non-data descriptors which return bound methods when they are invoked from an object. In pure Python, it works like this:
class Function(object):
. . .
def __get__(self, obj, objtype=None):
"Simulate func_descr_get() in Objects/funcobject.c"
if obj is None:
return self
return types.MethodType(self, obj)
Running the interpreter shows how the function descriptor works in practice:
>>>
>>> class D(object):
... def f(self, x):
... return x
...
>>> d = D()
# Access through the class dictionary does not invoke __get__.
# It just returns the underlying function object.
>>> D.__dict__['f']
<function D.f at 0x00C45070>
# Dotted access from a class calls __get__() which just returns
# the underlying function unchanged.
>>> D.f
<function D.f at 0x00C45070>
# The function has a __qualname__ attribute to support introspection
>>> D.f.__qualname__
'D.f'
# Dotted access from an instance calls __get__() which returns the
# function wrapped in a bound method object
>>> d.f
<bound method D.f of <__main__.D object at 0x00B18C90>>
# Internally, the bound method stores the underlying function,
# the bound instance, and the class of the bound instance.
>>> d.f.__func__
<function D.f at 0x1012e5ae8>
>>> d.f.__self__
<__main__.D object at 0x1012e1f98>
>>> d.f.__class__
<class 'method'>
Sync From: https://github.com/TheBigFish/blog/issues/14
版本为: codeblocks-17.12mingw-setup.exe
gcc: 5.1.0
将 `CodeBlocks\MinGW` 下文件拷贝至 `msys\1.0\mingw`
gcc -v 输出版本号即成功
strawberry-perl-5.30.0.1-64bit.msi
- 版本 openssl-1.0.2j.tar.gz
- 编译
- ./config
- make
- make test
- make install
编译后文件位于 `msys\1.0\local\ssl`
- project -> build options -> linker settings 增加:
- libcrypto.a
- libssl.a
- libgdi32.a
- project -> build options -> search directories 增加:
- msys\1.0\local\ssl\include
完成
Sync From: https://github.com/TheBigFish/blog/issues/13
tornado 的协程原理分析
版本:4.3.0
为支持异步,tornado 实现了一个协程库。
tornado 实现的协程框架有下面几个特点:
由此可见,这是 python 协程的一个经典的实现。
本文将实现一个类似 tornado 实现的基础协程框架,并阐述相应的原理。
使用 time 来实现定时器回调的时间计算。
bisect 的 insort 方法维护一个时间有限的定时器队列。
functools 的 partial 方法绑定函数部分参数。
使用 backports_abc 导入 Generator 来判断函数是否是生成器。
1 | import time |
是一个穿梭于协程和调度器之间的信使。
提供了回调函数注册 (当异步事件完成后,调用注册的回调)、中间结果保存、结束结果返回等功能
add_done_callback 注册回调函数,当 Future 被解决时,改回调函数被调用。
set_result 设置最终的状态,并且调用已注册的回调函数
协程中的每一个 yield 对应一个协程,相应的对应一个 Future 对象,譬如:
1 | @coroutine |
这里的 routine_simple() 和 sleep(1) 分别对应一个协程,同时有一个 Future 对应。
1 | class Future(object): |
这里的 IOLoop 去掉了 tornado 源代码中 IO 相关部分,只保留了基本需要的功能,如果命名为 CoroutineLoop 更贴切。
这里的 IOLoop 提供基本的回调功能。它是一个线程循环,在循环中完成两件事:
程序中注册的回调事件,最终都会在此处执行。
可以认为,协程程序本身、协程的驱动程序 都会在此处执行。
协程本身使用 wrapper 包装,并最后注册到 IOLoop 的事件回调,所以它的从预激到结束的代码全部在 IOLoop 回调中执行。
而协程预激后,会把 Runner.run() 函数注册到 IOLoop 的事件回调,以驱动协程向前运行。
理解这一点对于理解协程的运行原理至关重要。
这就是单线程异步的基本原理。因为都在一个线程循环中执行,我们可以不用处理多线程需要面对的各种繁琐的事情。
事件循环,回调事件和定时器事件在循环中调用。
执行一个协程。
将 run 注册进全局回调,在 run 中调用 func() 启动协程。
注册协程结束回调 stop, 退出 run_sync 的 start 循环,事件循环随之结束。
1 | class IOLoop(object):, |
协程装饰器。
协程由 coroutine 装饰,分为两类:
装饰协程,并通过注册回调驱动协程运行。
程序中通过 yield coroutine_func() 方式调用协程。
此时,wrapper 函数被调用:
协程返回 Future 对象,供外层的协程处理。外部通过操作该 Future 控制协程的运行。
每个 yield 对应一个协程,每个协程拥有一个 Future 对象。
外部协程获取到内部协程的 Future 对象,如果内部协程尚未结束,将 Runner.run() 方法注册到 内部协程的 Future 的结束回调。
这样,在内部协程结束时,会调用注册的 run() 方法,从而驱动外部协程向前执行。
各个协程通过 Future 形成一个链式回调关系。
Runner 类在下面单独小节描述。
1 | def coroutine(func): |
因为没有使用 yield from,协程无法直接返回值,所以使用抛出异常的方式返回。
python 2 无法在生成器中使用 return 语句。但是生成器中抛出的异常可以在外部 send() 语句中捕获。
所以,使用抛出异常的方式,将返回值存储在异常的 value 属性中,抛出。外部使用诸如:
1 | try: |
这样的方式获取协程的返回值。
1 | class Return(Exception): |
Runner 是协程的驱动器类。
self.result_future 保存当前协程的状态。
self.future 保存 yield 子协程传递回来的协程状态。
从子协程的 future 获取协程运行结果 send 给当前协程,以驱动协程向前执行。
注意,会判断子协程返回的 future
如果 future 已经 set_result,代表子协程运行结束,回到 while Ture 循环,继续往下执行下一个 send;
如果 future 未 set_result,代表子协程运行未结束,将 self.run 注册到子协程结束的回调,这样,子协程结束时会调用 self.run,重新驱动协程执行。
如果本协程 send() 执行过程中,捕获到 StopIteration 或者 Return 异常,说明本协程执行结束,设置 result_future 的协程返回值,此时,注册的回调函数被执行。这里的回调函数为本协程的父协程所注册的 run()。
相当于唤醒已经处于 yiled 状态的父协程,通过 IOLoop 回调 run 函数,再执行 send()。
1 | class Runner(object): |
sleep 是一个延时协程,充分展示了协程的标准实现。
流程如下图:
1 | def sleep(duration): |
1 | @coroutine |
运行输出为:
it is simple routine
routine_ur url0 took 1s to get!
it is simple routine with return
value from routine_simple_return
routine_url_with_return url1 took 1s to get!
('url1', 1)
routine_url_with_return url2 took 2s to get!
('url2', 2)
可以观察到协程 sleep 已经生效。
author:bigfish
copyright: 许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议
Sync From: https://github.com/TheBigFish/blog/issues/12
1 | vi ~/.bashrc |
1 | vi ~/.bashrc |
1 | vi ~/.cargo/config |
1 | // main.rst 文件顶部增加 |
Sync From: https://github.com/TheBigFish/blog/issues/11
StackContext allows applications to maintain threadlocal-like state
that follows execution as it moves to other execution contexts.an exception
handler is a kind of stack-local state and when that stack is suspended
and resumed in a new context that state needs to be preserved.一个栈结构的上下文处理类
异常处理也是一个栈结构的上下文应用
1 | @contextlib.contextmanager |
1 | from __future__ import with_statement |
1 | class _State(threading.local): |
全局上下文保存整个执行程序的上下文(栈)
with StackContext(context) 使程序包裹在 (global_context, context) 上执行
执行完成后恢复全局上下文
1 | class StackContext(object): |
捕获上下文执行中抛出而又未被捕获的异常
作用类似 finally
用于执行在程序抛出异常后记录日志、关闭 socket 这些现场清理工作
如果 exception_handler 中返回 True, 表明异常已经被处理,不会再抛出
1 | from tornado import ioloop |
__exit__ 中捕获 with 语句所包裹的程序执行中所抛出的异常,调用注册的 exception_handler 进行处理
exception_handler 返回 True,则异常不会蔓延
1 | class ExceptionStackContext(object): |
临时构造一个空的全局上下文
1 | class NullContext(object): |
之所以进行这样复杂的操作,是为了对某些前面执行环境相同的情况省略前面的构造,节省时间,否则,可以用一行代替:
new_contexts = ([NullContext()] + [cls(arg) for (cls,arg) in contexts])
1 | def wrap(fn): |
author:bigfish
copyright: 许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议
Sync From: https://github.com/TheBigFish/blog/issues/10
tornado 的异步上下文机制分析
我们实现一个简单的 MyIOLoop 类,模仿 tornado 的 IOLoop,实现异步回调
实现一个简单的 MyStackContext 类,模仿 tornado 的 StackContext,实现上下文
模拟 tornado IOLoop
1 | class MyIOLoop: |
由输出可以看到,回调函数 call_func 中抛出的异常,在 main 函数中无法被捕获
main 函数只能捕获当时运行的 async_task 中抛出的异常, async_task 只是向 MyIOLoop 注册了一个回调,并没有当场调用回调
call_func 函数最终在 MyIOLoop.start 中调用,其异常没有被捕获
1 | my_io_loop = MyIOLoop.instance() |
可以使用 wrap 的方式,把函数调用和异常捕捉写在一起,回调实际调用的是带异常捕捉的函数 wrapper
1 | my_io_loop = MyIOLoop.instance() |
由此,可以想到,构造一个上下文环境,使用全局变量保存这个执行环境,等回调函数执行的时候,构造出这个环境
下面模仿了 tornado 异步上下文实现机制
这样,在 main 函数中执行
1 | with MyStackContext(my_context): |
构造一个执行上下文 my_context,异步函数将在这个上下文中调用
效果上相当于在 my_context 这个上下文环境中调用 async_task
类似:
1 | def my_context(): |
1 | import contextlib |
Tornado 源码分析(二)异步上下文管理(StackContext)
author:bigfish
copyright: 许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议
Sync From: https://github.com/TheBigFish/blog/issues/9