Skip to content

{ Author Archives }

How to Write A Simple Micro Kernel

Intro Hello, everybody.  You are here to learn how to write a simple micro kernel for ARMs.  Last year, I wrote a very easy micro kernel which named Totoro, spent about two months in my spare time.  I remember that i was very very excited when the kernel works.  Maybe, like Linus Torvalds when he got […]

时间

假如有一天我们能够站在宇宙的中心,环顾整个宇宙的深邃,我们便会知道自己的渺小,连地球也只是这银河里的一颗星。时间,却似是最深不可测的,什么是时间?流逝的时间,又到了哪里?宇宙是一个密闭的空间吗?它和时间的关系是什么?如果宇宙是密闭空间,那宇宙的边缘是什么?如果宇宙无边无际,是否它就是时间?人类越是对此的无知,越充满了神秘。

艺术

上世纪 92 年 12 月 21 日,我诞生在一个平凡的乡村家庭里,一个新生命的诞生,和所有平凡的孩子一样,长大。今天想谈谈,从小刻在脑海里的那一抹关于艺术的记忆。我的父亲,从我知事以来,他就一直奔波在福建与广东两省,他是村里为数不多的大卡车司机。小时候,对父亲的所有印象,可以用严肃一词加以概括。但往往,让我受益的却是潜藏在他思想里的,未曾实现的绘画艺术。我和弟弟也看过父亲画的一副画,那是一副摩托车素描,可以用生动传神来描述吧,总之,对严肃的父亲又多了一个情感,崇拜。也听一个隔壁堂哥说过,父亲以前不爱上学的时候就跑到农场里,在墙壁上画画。有一次,我自己一个人去那个地方找了找是否还有他的真迹,无奈大部分墙都已经塌掉,上面倒是有点乱涂的痕迹,那当然不是我父亲的作品。也对,堂哥说的时候我已经好几岁了,而我父亲读书的时候也才十几岁,当年的艺术早就在历史的洪流里了。仅仅是因為这个,我小时候也突然有段时间喜欢上了画画,画的不是龙就是雕,龙仿照的是我家日历上的画,雕是仿照雕牌洗衣粉包装袋上的雕,当时只想着它们是萧峰召唤的神龙,杨过身旁的神雕。 今天还想谈谈上世纪八九十年代的香港艺术家,张国荣。不知道从什么时候开始,我的乐单里,大部分歌曲来自张国荣。由此,我还发表过一系列较为极端的言论:中文歌曲的精华在粤语歌曲,粤语歌曲的精华在张国荣。这肯定要招来大批量的口水了,无奈我几乎没有粉丝,便没有收到多少口水。吐口水当然是不文明的。话说回来,为什么我会如此爱粤语,特别是张国荣的歌曲?我也曾对自己问过,我想可能有以下几点原因:1)这种对歌曲喜爱掺杂了其他情感,对张国荣个人的品性加分,颜值加分; 2)粤语歌曲带有很特殊地域风情,而老爸常年混迹与广东,对此能加分; 3)对普通话大部分垃圾歌曲的排斥导致逆向加分,对闽南歌曲不温不热导致的逆向喜爱; 4)张国荣唱工一流,用心,用情。 我很快发现,第四点是主要的因素,而第一点在第四点的基础上进行了放大,放过来又作用在了第四点。第二点有点站不住脚。偶尔第三点再给一个逆向撞击,比如听到了某普通话歌曲,难听,娇柔造作,心灵空虚,无病呻吟,小家子气等等。然而,我第一次听到张国荣的时候,并不知道他的故事,也未曾听过他的歌曲,即时是家喻户晓的倩女幽魂我都不知道是其大作。这里也可能有个加分。但是,听张国荣已经有一年多,如张国荣自己所说,他对歌曲的诠释是用情去唱,几乎每首歌曲都可以从中体会出传唱者真实而细腻的情思,因此其艺术天赋才是征服我的主要因素。从小时候的刀郎,林俊杰,到大学的五月天,似乎都没有一个真正唱到人心里的。而他,张国荣,做到了。現在我却不想拿张国荣和任何歌手去比较,他不是纯粹的歌手,他是几个世纪以来,真正用艺术去诠释人生的艺术家。他的每首歌能带出每个不一样的故事,风格似变化多端,但用心用情二词却是贯穿始终。张国荣坦言,自己在唱歌上没有花太多余力,录歌曲经常就是一次性通过,香港著名歌手许冠杰也曾为此打趣自己得录多次才得以满意,实在不及张国荣,当然是有谦虚。声线及完美的音质让张国荣在中音歌曲,甚至高音歌曲上创造了一个又一个神迹,这可能就是天赋吧。细细数来:无心睡眠,侬本多情,共同渡过,拒绝再玩,想你,沉默是金,侧面,暴风一族,似水流年,滴汗,风再起时,千千阙歌,我,玻璃之情,最爱,挪亚方舟,红,由零开始,客途秋恨,芳华绝代,你在何地,今生今世,有谁共鸣,Monica,缘分,Thank You,寂寞夜晚,红蝴蝶,枕头,这些年来 ….. 他带给世界的有太多太多的美好。而演绎生涯上,他何尝又不是创造了一个又一个经典。如今,哥哥已经离我们远去十几载,其经典的艺术仍然为我们所爱。 附一曲:无心睡眠 -张国荣

Socrates: A Privacy Plugin for Centralized IM Applications

https://io-lab.net/archives_text/socrates.txt

平整三角形:安全,分散,可讀的人名

當使用電腦時,我們喜歡用名字來指代事物。例如,這個網站被稱為“www.aaronsw.com”。你可以在瀏覽器中輸入並閱讀這些文字。我們可能需要從這些名稱中選擇三個大屬性: 安全:當你在你輸入的名字,實際上得到我的網站,而不是冒名頂替者的網站 分散:沒有中央當局控制所有的名字 人類可讀的:這個名字是你實際上可以記住的東西,而不是一串長長的隨機性字符串 在一篇經典的論文中,我的朋友 Zooko 爭辯說,在任何時候最多可以獲得這些屬性中的兩個。 最近,DNS 傳奇人物丹·卡明斯基(Dan Kaminsky)用這個說法認為,由於電子現金幾乎與命名一樣,Zooko 的三角形也適用於它。他用這個說法認為 BitCoin 電子現金系統同时具备安全,分散,并且具有可读意義是不可能的。我有 BitCoin 的問題,但這顯然不是不可能的,所以我只是假設 Kaminsky 在某個地方出了問題。 但今晚我意識到你確實可以使用 BitCoin 來平整 Zooko 的三角形。以下是它的工作原理: 讓一個叫做滾動的文檔。滾動由一系列行組成,每行由一個元組(名稱,密鑰,隨機數)組成,這樣從一行的開始到結尾的滾動散列的前 N 位都是零。因此,要為滾動添加一行,需要做足夠的計算來發現導致哈希位為零的適當的隨機數。 要查找名稱,向每個人您所知道的具有滾動的人詢問信息,並相信最長的滾動條,然後從頭開始,以您正在查找的名稱的第一行作為關鍵字。要發布名稱,您會找到適當的隨機數,然後將新行發送給您認識的所有人。 好的,讓我們暫停一下。你如何在這樣的系統中竊取名字?首先,你需要計算一個新的隨機數,用於你想要盜取的行和每一個後續行(Gimcuan Hui 註:之所以也要計算後續行,因為 BitCoin 裏面的每次交易都被鏈接(Chain)在一起,改變一個工作記錄,後面的記錄如果沒有跟著修改就會對不上)。其次,您需要將替換捲軸交給用戶。第一點是困難的,但也許並非不可能,取決於你想要偷的名字有多少行。它需要網絡的其餘部分的 CPU 功率的大部分倍數。這對我來說似乎是一個相當強的約束,但對於 Dan 來說顯然不是。幸運的是,我們被第二個問題拯救了下來。 讓一組機器稱為網絡。每個人都記得它最後一次被信任的捲軸。當創建一條新的有效行時,它會被發送給網絡中的每個人,並將其添加到他們的捲軸中。現在,不可能竊取舊名稱,因為網絡中的機器只添加新名稱,不接受舊名稱的替換。 對於已經在網絡中的機器來說沒問題,但你如何加入?那麼,作為一個物理定律,加入一個網絡需要至少有一台機器已經在網絡中。現在,當你加入時,那台機器可以給你一個虛構的捲軸,他們偷走了所有的名字。我不認為有什麼辦法可以避免這種情況 – 如果你不認識任何一個願意告訴你正確的答案的人,你不能在空氣中找到正確的答案。即使是一個中心化的系統也至少依賴於一個誠實的根。 您可以在連接時了解多個節點並詢問每個節點的滾動情況,從而改善此問題。似乎理論上最好的情況是只要求一個節點是誠實的。這相當於信任哪個節點具有最長的滾動。但是這會讓你容易受到以下攻擊者的攻擊:a)具有足夠的 CPU 能力來製作最長的捲軸,並且 b)可以至少選擇一個初始節點。另一種方法是只信任從大多數節點列表中收到的捲軸。這使您容易受到可以控制大部分初始節點的攻擊者的影響。您大概選擇哪種折衷取決於您相信您的初始節點的多少。 發布虛假滾動等同於分割命名空間並啟動單獨的網絡。(我們可以通過要求節點簽署每個最新的捲軸並發布它們的簽名來認證網絡的成員身份來強制執行此操作,任何試圖簽署兩個相互矛盾的捲軸的節點顯然都是雙重的並且可以打折扣)。另一種描述場景(b)的方式是,為瞭加入一個網絡,你需要一個節點列表,其中至少大多數實際上是網絡中的節點。這似乎不是一個過分艱苦的要求。 而且我們實際上比這更安全一些,因為大多數人需要相當數量的 CPU 才能保持合理。 如果我們假設您從一些帶外源聽到新名稱,讓他們在攻擊者的網絡上工作,攻擊者必須有足夠的 CPU 為您可能使用的每個名稱生成行。 否則,您會意識到,您在計算機上輸入的名稱在他人的計算機上工作時會返回 404,並且開始意識到您已遭到攻擊者的攻擊。 所以你有瞭這樣一個繫統。 名字是安全的:他們可以通過任意長度的鑰匙識別,不能被盜。 它們具有可讀意義:名稱可以是任何你喜歡的字符串。 […]

如何写一个IM

导言 本文将介绍如何在 TOX 内核上编写一个可以进行文本交流的 IM (Instant Messaging) 软体。 TOX TOX 是什么?它是一个分布式的 p2p 网络协议。准确来说,它提供了这样的一个网络协议的各种接口,包含安全加密、DHT 网络、洋葱路由等核心部件的实现,以及朋友请求与连接对话、群聊等模块的实现,它还包含了音视频库以供用户实现音视频交流的功能。我们要做的是调用它封装好的这些接口,来实现自己的 IM 软体。整个 TOX 采用 C 语言实现。从我这周的使用测试情况来看,TOX 内核极其稳定。这样一个优秀的去中心化内核软体,值得所有在这方面感兴趣的应用开发者在其基础上开发一个自由的 IM 软体。本文也会在最后一节列出基于此开发出来的 IM 软体。 Tox Core 首先获取 tox 核心代码: git clone https://github.com/TokTok/c-toxcore 按照 c-toxcore 里面的指导编译,安装 c-toxcore,例如: cd c-toxcore git checkout v0.2.2 cmake . make sudo checkinstall 如果你使用的是 Debian 系统,并且采用了 checkinstall 的安装方式,那么在执行 sudo checkinstall 命令时需要在安装提示的时候设置好软件的版本,比如我们这里的 0.2.2 版本。 […]

Sunrise: A Song of Two Humans

“God is giving you, in the holy bonds of matrimony, a trust. She is young…and inexperienced. Guide her and love her… …keep and protect her from all harm.”

如何写一个微内核

导言 有时常关注我博客的朋友知道,去年我自己开发过一个很简单的微内核 Totoro,目前已经暂时停止更新。从开发到能真正运行花了一两个月的时间,当然都是我在业余时间做的啦。还记得当时那种兴奋的心情,可能跟 Linux 的最初开发者 Linus 差不多,有兴趣可以看这篇文章 Linux – a free unix-386 kernel 。 当然了,水平毕竟不是一个层次的。不过今天,我想把如何开发这样一个简单的内核给记录下来,一来是让有兴趣的后来者可以很快的摸到门路,二来是做一个阶段性的总结,再来就是看看自己还有没有兴致继续把它做得更好,毕竟现在漏洞百出,也不可能给别人拿去用。总的来说,出来做了三年的软件开发,没做过什么高端的有难度的东西,这样一个作品让我自己还是比较开心的! 关于单线程 从单片机(又称单板机)玩过来的同学应该知道,我们刚开始写代码的时候,几乎都是裸奔在处理器上的。写个流水灯,点亮数码管,高端点的来个串口打印。这对刚接触的同学其实就有很多东西可以学了。但是人也总不会一直停步不前,写了太多的单线程代码的菜鸟开始思考,多线程到底多了什么了呀?说到这其实我很想笑,假如你去问一问那些入门语言是 Java,Python 的同学,他们一定会说,多线程有什么了不起啊!对呀,对这些这些高级语言来说,多线程?开玩笑,随便调个接口,要几十个线程,甚至几百个,分分钟给你造好了。在这些人眼里,这个东西,没什么了不起。但对于出身即低端又比较吝啬的嵌入式的同学们来说,这个多线程词汇,却魔咒般的充满了太多的神秘感。那么多线程到底指的是什么?我们不去讨论太复杂的东西,不去讨论进程空间,虚拟内存等等高端神秘的词汇。我们只关注上下文环境。这个对于容易满足的嵌入式开发者来说,已经很知足了。时常感慨,是不是嵌入式开发做久了,人也会对自己变吝啬。 上下文环境 上下文(Context)环境,指的是这个线程运行时的一些状态,比如局部变量的值,寄存器里保存的值,比如,PC 指针指向那里,代表程序即将运行到那里,SP 指针,记录了调用信息,LR 记录了回去的路(返回地址)等等。那么要实现这个多线程我们需要做些什么? 保存上下文。我们在做线程调度的时候,将当前线程的上下文环境保存在那个线程申请的“栈”内存里(其实就是一个大数组)。然后通过一系列的底层操作,将要被调度的线程唤出来。其实也就是把之前保存的上下文从内存里读到寄存器上啦,只不过这个过程需要一些技巧,我们会在代码解析里面讲到。其实多线程就是这样的啦,那么我的这篇文章是不是该完结了?不尽然,我们要做到微内核的基本功能,那还得有调度器呀。 傻逼式调度器 我们要实现这样一个调度器。对于平级线程,也就是优先级一样的应用线程,我们会去分片(Time-sharing)执行它们。对于高优先级应用线程,我们会义无反顾的一直执行它,直到它愿意自己挂起。我觉得这是最自然的调度器,因为优先级既然高,那么也就得优先执行。当然,也是很傻逼的调度器啦。我们现在的目标是,保持一切尽量的简单。这样才有兴趣继续干下去嘛。这样约定好了以后,我们开辟了两个队列,一个用于保存处于准备态的线程,一个用于保存挂起的线程。而当前运行的进程会由一个 current 任务结构体指针来标记。所以一个任务执行完之后会有两种状态,一个是挂起,一个是再次处于准备状态。这样我们就需要一个链表接口模块。 基础数据结构 我们用单链表结构来实现这两个队列。 include/totoro/taskq.h struct tasklist { struct ttr_tcb *tcb; struct tasklist *next; }; 实现单链表的几个接口: static struct tasklist *migrate(struct ttr_tcb *tcb, struct tasklist **src, struct tasklist **dst) […]

Linux – module_init

Linux 利用了程序编译链接的一个技巧,在GCC里可以通过 __attribute__ 将指定代码放入到某个特定的段(section)中,内核模块就是这样被统一管理起来的。如图中所示,指向模块初始化代码的函数指针都被放置在一个 “.initcall6.init” 的代码段里,而模块初始化代码则放置在另一个代码段 “.init.text”。这样的好处就是内核启动时加载内建(built-in)内核模块阶段可以很方便地根据首指针依次将所有模块遍历出来,这有点像 Unix 哲学中将代码复杂度转移到数据上去寻求简洁,事实证明这样干确实简洁漂亮。 结合代码看图:Fig 1. snapshot of *_module_init in kernel image drivers/usb/serial/cp210x.c include/usb/serial.h    module_usb_serial_driver(serial_drivers, id_table) init/main.c include/asm-generic/vmlinux.lds.h    do_initcalls      initcall_levels include/linux/module.h include/linux/init.h    module_init(x)      __initcall(fn) 外部链接: 1,https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html

细谈 C 之 sizeof

ANSI C 对 sizeof 的定义 (6.5.3.4 The sizeof operator): 限制 ( Constrains ) 1,sizeof 不能作用在以下类型上: 函数类型 未完成类型 位成员 语法 ( Semantics ) 2,sizeof 的结果是操作数的字节数大小,类型为无符号整型。 如果数组长度可变,那么会评估它的大小; 如果数组长度固定则返回一个常数; 3,具体的说: 如果是 char, unsigned char signed char 则返回 1; 如果数组长度固定则返回数组的字节大小; 如果是结构体或者共用体则结果就是这个类型实例的总大小; 举几个例子: 32 bit 系统上: sizeof (char) -> 1; int a[2]; sizeof (a) -> 8; 4,sizeof 的返回结果由具体编译器实现,类型是 size_t ,见 […]