Browsed by
Category: 计算机系统原理

[Linux 0.11] Draft 6 IA32架构下多任务的硬件支持

[Linux 0.11] Draft 6 IA32架构下多任务的硬件支持

Overview 支持多任务的硬件结构为 Task Register (TR) Task State Segment (TSS), LDT 以及 Task Gate。而最核心的,存储任务上下文信息的就是 Task State Segment, 下面对其进行详细的说明 TSS基本数据结构 GDT, LDT TSS(Task State Segment)  has its own descriptor called TSS Descriptor Structure of 32 bit TSS, store the context and link to previous task, and 3 different privileged Stack 下面对一些比较关键的部分进行介绍 Previous Task Link: 存储的是上一个任务的选择符 LDT Segment Selector: 存储的是这个Task使用的LDT I/O Map Base Address: I/O Map的基地址(要对 I/O Map 是什么进行进一步的解读: I/O Map 包含一个权限Map和一个Interrupt redirect Map) TSS 描述符的一些说明 TSS Descriptor 用于描述 Task State Segment 的描述符,当选择符的TI…

Read More Read More

[Linux 0.11] Draft 2 80386 System Architecture

[Linux 0.11] Draft 2 80386 System Architecture

此文对 Intel 80386 的系统架构进行一定程度的说明 80386 在系统层面支持下面的功能 保护 内存管理 多任务 IO 异常和中断 初始化 协处理器,多处理技术 调试功能 上述均通过系统寄存器以及指令来支持,下面会对这些进行介绍 系统寄存器(Registers) 系统寄存器分为如下几类 EFLAGS 内存管理寄存器 控制寄存器 (Control Registers) 调试寄存器 (Debug Registers) 测试寄存器 (Test Registers) 下面对每一类寄存器进行说明 System FLAGS EFLAGS 中的 System FLAG 可以控制如 IO, 可屏蔽中断,任务切换,调试等功能。 IF: 用来控制系统是否接受(可屏蔽的)外部中断请求 IF = 0 为屏蔽 NT: 此位用于控制 Chain interrupted 以及 called tasks, 该位会影响 IRET 指令的操作方式 RF: debug 有关的 flag TF: debug 有关的 flag,将处理器设置为单步执行模式,在这个模式下,所有的指令CPU都会产生一个异常,可以在每一个指令处停下来进行调试 VM: 用于进入 Virtual 8086 Mode 的 flag 这里不做解释 内存管理寄存器 与内存分段管理相关的寄存器,如全局描述符表,中断描述符表,也就是 GDT, LDT, IDT 和 Task 的描述信息存储用的寄存器 GDTR LDTR…

Read More Read More

[DFS #0] HDFS论文解读

[DFS #0] HDFS论文解读

参考论文: The Hadoop Distributed File System 分布式文件系统HDFS作为HBase的下层服务,以及众多存储服务的支持项目,已经被广泛使用,下面通过解读上述论文来记录并介绍一下HDFS的架构,以及功能,还有设计 整体架构 Overview 如图所示     每一个HDFS集群由一个NameNode,多个DataNode,以及BackupNode, CheckpointNode组成,上图中的三角形为使用HDFS的客户端,客户端和DataNode之间的线表示客户端到DataNode的物理距离,对于这个架构,有下面几点要说的 一个集群的NameNode只有一个,客户端想要使用这个HDFS的时候,一定是先和NameNode进行交流,获得需要的DataNode信息之后,才能和DataNode进行通信 因为NameNode只有一个,所以NameNode如果出现单点故障可就不好玩惹,而且对于存储这种要求数据一致性很高的系统,也不能容忍NameNode出故障系统就瘫痪这种情况,因而使用CheckpointNode和BackupNode对NameNode进行备份,他们的区别和备份方式下文会详细说 NameNode不会主动去和DataNode通信,他们之间的通信是这样的: DataNode每隔一定时间发送heartbeat到NameNode(默认3s)(通知NameNode他还活着可以干活=w=(划掉 ,然后NameNode在这个时候会将要发送到DataNode的指令通过Response的形式发送到DataNode Client对数据的操作精简来看,无非是读写两种,当Client想要读取HDFS的数据的时候,首先Client先去询问NameNode,哪些DataNode有他要的数据,并且选择距离他最近的DataNode,然后Client直接连接距离最近的DataNode并获取数据 e.g: 如上图的ClientA想要获取一个数据,且数据在DataNode A B C内都有存放,那么ClientA首先要和NameNode进行通信,获得DataNode列表(ordered by distance to the client)然后选择距离它最近的DataNode B进行通信获取数据 当Client想要向一个文件写入数据的时候(无论文件存不存在),其他的Client会无法对此文件进行写入操作(以此来保证文件不会因为同时写而corrupt data)写入完毕之后,会将Block进行Replica复制到不同的DataNode上(默认为复制3份),具体会在下面介绍   模块 & 术语 NameNode HDFS Namespace ,是存储着所有DataNode以及每一个DataNode上的文件的元信息的一个目录结构,NameNode通过inode的方式来表示每一个文件和文件夹。Namespace 就可以理解为Linux的目录树的inode list,每一个inode指向一个datablock,datablock存在datanode上 HDFS将整个Namespace放在RAM内,完整的文件系统信息(包含inode信息,以及每一个inode对应的Datablock list 元信息)称为Image, Image持久存储在NameNode本地存储里,称为一个Checkpoint, NameNode同时维护了数据操作的日志journal DataNode 显然,这就是数据真正存放的地方,每一个Datablock由两个文件组成,该Block的数据,和该Block的[checksum,创建时间]信息组成的元数据 如下图 一个占3个Block的文件存放在DataNode里的情况简图,该文件有三个block,每一个block的信息含有Data & MetaData,三个Block组成了整个文件file1, 然后在NameNode的某一个inode存储着信息对应着文件名file1,block数3,物理位置在该DataNode上 DataNode的Startup   当DataNode Startup时,会和NameNode进行handshake,进行namespaceID(每一个HDFS都有一个唯一的NamespaceID,在创建HDFS的时候就确定了)&version的认证,二者必须均与NameNode完全一致,如果不一致的话,该DataNode就会停止工作。保证了不会因为错误的NameNode或者软件版本不兼容而导致数据出问题, 如果这个DataNode没有保存任何Namespace信息,说明这是一个新的DataNode,没有任何Block数据,因而允许加入此HDFS cluster。 当DataNode握手成功之后,会register自己到该NameNode,如果为第一次加入该NameNode,则会被NameNode分配一个唯一的StorageID,并且永远不会改变,DataNode会将此ID持久存在自己的storage中,这个StorageID保证了就算IP变动或者端口变动,NameNode仍然可以识别该DataNode的身份 DataNode与NameNode的通信 Block Report: Block Report是DataNode用于通知NameNode自己所持有的Block的信息(如blockid,block大小,generation stamp)的一种数据,因为这个数据是会随时改变的,所以需要定期发送Block Report给NameNode,使得NameNode能得到整个Block分布的信息。当DataNode注册到NameNode时,会立即发送一个Block Report,之后会每隔一段时间(1h)发送一次BlockReport HeartBeat:  DataNode通过定期的心跳与NameNode进行通信,使NameNode确认DataNode存活,并且同时carry其他信息,如存储可用量,目前正在传输的数据量等信息,用于NameNode进行负载均衡。 NameNode则在收到DataNode心跳,对DataNode进行Response的时候进行通信,可以发送的指令有: 将自己持有的数据块复制到其他DataNode 移除该DataNode上的数据块 重新注册、或者停止该DataNode 使DataNode立即发送一个Block Report Block Scanner 每一个DataNode都有一个BlockScanner,周期性地对Block的完整性进行认证 当Block…

Read More Read More

[Linux 文件系统]一张图解释什么是硬链接什么是软链接

[Linux 文件系统]一张图解释什么是硬链接什么是软链接

= = 不知道我有多久没更新博客了(观众: 这种好吃懒做不上进的博主赶紧打包卖到幻想乡被妖怪吃了吧) 我: 诶, 真不错诶! 快把我打包去幻想乡窝要见灵梦还有紫妈!    *&^X^(**啊窝错了&^#^@*#@(*不要这么对我*Y*)IH* [博主被打包中… 请稍后] 这么久没更新博客真的是很抱歉 各种事情加上自己最近也没有继续研究太多底层相关的东西, 公司的项目的体量有点大导致窝晚上回来没有好好码字学东西qwq, 好了闲话就说到这里, 下面是正文 Linux 文件系统里的硬链接(hard link) 和软(符号)链接 (softlink) 很多刚刚接触Linux文件系统的同学包括有些接触了文件系统一阵子的同学还是会对软链接和硬链接有疑问, (比如我, 划掉)那么下面我们就借助一个简单的例子来了解一下什么是软链接什么是硬链接, 概念我就不说了, 想要看这个文章,首先要懂得什么是inode, datablock, 下面我们在tmp文件夹下做一个小实验 mkdir havefun cd havefun echo “Hello hard&soft link” >> void001 ln void001 void001.hard ln -s void001 void001.soft 好辣, 我们现在就已经创建了一个叫做void001的文件,以及她的软和硬两个链接, 窝们如何区分软硬链接呢? 首先, 软链接在ls的时候(–color=auto/always)会用特殊的颜色标明出来, 不过这不是本质区别啦= =, 本质的区别在于, 软链接会占用一个新的inode, 而硬链接, 不会占用新的inode, 只是在目录block中增添了一条目录项记录, 并且指向了void001对应的那个inode. 为了证明我们上述说的,我们用ls -ali来看一下(画外音: -ali 才不是阿里呢, 只不过凑巧被窝排成了这个顺序而已), 下面的输出结果为了与图片的信息完全匹配, inode index被窝处理过了, 只是把数字进行了一个替换而已, 不影响解释原理, 原本的数字用括号注明了 [email protected]:/tmp/havefun# ls -ali total 8 4723004 drwxr-xr-x 2 root root…

Read More Read More

[不是科普向?] RE: 从零开始的操作系统开发 第二集

[不是科普向?] RE: 从零开始的操作系统开发 第二集

[本文概念性内容较多, 看图党慎入] 概要 Hmm, 第一集中我们已经学会了如何让计算机在启动的时候加载并运行我们写好的bootsector, 并且通过使用BIOS提供的中断控制显卡在屏幕上输出特定的字符串, 慢慢的我们已经熟悉了16bit下的底层程序的开发, 不过就如我们综述中所说, 16bit下我们能够访问的内存十分有限, 因此我们不得不离开这个我们熟悉但是却不好用(qwq)的16bit模式,切换到32bit下, 切换之后我们就可以在C语言内继续我们的操作系统的开发了, 我们的引导程序实际上做的事情就是, 将模式切换到32位,并且将操作系统所在的磁盘扇区装载到内存里, 然后call我们的操作系统的main函数所在的地址, 这样, 整个引导程序的使命就完成了, 下面的工作就是操作系统的事情了, 本文我们主要介绍如何切换到32bit下的具体操作, 以及在32bit下控制显卡输出特定的字符 本文最后实现的效果的具体代码在github上均可获得 代码仓库地址见第一集 全局描述符表(Global Descriptor Table GDT) 我们已经熟悉了16bit下的内存的分段结构以及逻辑地址转换为内存的物理地址的方式, 现在再来回顾一下, 16位下我们想访问内存需要提供两个信息, 段地址+偏移量,  这两个信息决定了物理内存的地址, 决定的方法是 Segment Addr * 16 + Segment Offset  这个可以在16进制上形象的表示为 Segaddr << 4 + Offset, 那么现在我们要切换到 32bit保护模式下, 之前的这个内存的段-偏移量模型已经不适用了, 取而代之使用的是个功能更加强大的模型, 支持对内存的某个部分进行保护, 权限控制, 以及提供虚拟地址访问的内存模型. 另外,在CPU由实模式(16bit, 下略)切换到保护模式(32bit, 下略)下后, 将逻辑地址映射到物地址的方式也发生了改变, 这个改变, 和我们这个小标题提到的GDT密切相关, 下面我们就来具体的介绍一下 GDT   什么是GDT GDT是由多个SD组成的一个数据结构, 每一个SD, 称作Segment Descriptor, 包含了一个段的各种元信息如下:  基地址(BaseAddress) 定义了这个段在内存中的物理的起始地址  段上限(Segment Limit)定义了段的大小 标志位数组, 这些标志位向CPU说明CPU应该如何处理这个段中的内容, 如本段只读, 或者本段可执行等, 相当于这个Segment的属性 每一个SD是一个8Byte长的数据结构, 通过64个bit存储了所有上述信息, SD的结构如下: 我们可以看出来比较反人类的地方是这个数据结构存储的不同类型的数据信息并不是连续的= =…

Read More Read More

[科普向?] Re: 从零开始的操作系统开发 第一集

[科普向?] Re: 从零开始的操作系统开发 第一集

Hmm, 果然还是开坑了~! 在学校智障的操作系统课设的发起下, 再加上每个程序员都有一个写一个自己的操作系统的公主梦(雾), 我们愉(作)快(死)地开坑啦~ 以前曾经跟着 “30天自制操作系统” 玩过DIY操作系统, 不过那个书更像面向小白, 讲的东西也不够系统, 而且使用的是自己改过的nas汇编器, 因而不能算写过, 这一次则是真正的开坑啦~ (虽然课设时间很短写出一个完整的根本不可能不过慢慢写总会写完的你说对不喵~) 我们的开发过程在Bearychat上直播 neugeek.bearychat.com 的Toy-OS频道, 我们的git-repo 为 https://github.com/VOID001/toy-os 菊苣们不要喷, 既然挖了坑窝就不会不填(….你都已经挖了多少个坑了啊喂! (逃)) 这个系列的文章将会记录在开发操作系统的整个过程中的一些经验&心得&吐槽 不知道会有多少集(   参考资料们: MIT 的 XV6 源代码 & handbook University of Birmingham 的 Writing an simple operating system from scratch Quora, StackOverflow Jiong Zhao Linux 0.11内核完全注释   我们使用的工具链: GNU Assembler & GNU C Compiler Qemu Gdb objcopy, objdump, binutils, elfutils GNU Makefile   操作系统编写总览 什么是BIOS 参考阅读: http://whatis.techtarget.com/definition/BIOS-basic-input-output-system 我们的定位是写一个操作系统,那么首先我们应该了解,整个操作系统都应该由哪些模块构成, 那么就让我们从操作系统的启动说起, 说到这里就不得不说一下BIOS, BIOS是Basic Input and Output System, 是你的计算机加电运行后加载的第一个程序, 它是固化在你的EPROM内的一个程序片段…

Read More Read More

setcap wine 遇到的问题解决

setcap wine 遇到的问题解决

之后为了让普通用户也能通过wine访问到网络接口,需要给wine的相关程序(wine-preloader 和 wineserver wine) 一些特权   参考  man capabilities 和 setcap  首先需要给CAP_NET_RAW 权限 这个要给到 wine-preloader 上,不过在设置完这个权限之后,执行 wine XXX.exe 会报错 wine: error while loading shared libraries: libwine.so.1: cannot open shared object file: No such file or directory 这是因为特权模式的程序运行的时候是不会检测到相对路径的lib库的, 具体参考文章如下:http://stackoverflow.com/q/6493846/296473  解决方法在文中已有了 就不赘述了  上述问题解决后,运行wine 会提示  Internal errors- Invalid parameters  , 而且winedbg不可以attach到进程, 这个问题的解决方法是给wineserver(不是wine-preloader)CAP_SYS_PTRACE权限    

__attribute__ in C

__attribute__ in C

__atrribute__ in C Take a look at this code for example (in Cygwin master branch /winsup/cygwin/winsup.h) #include<stdio.h> __attribute__((constructor)) void fun1() { printf(“Hello “); } __attribute__((destructor)) void fun2() { printf(“Worldn”); } int main(void) { return 0; } Then gcc xxx.c and then run the code it will print out “Hello World” ~ So why it works? The code with constructor attribute run before main function and code with destructor attr run after main function The __attribute__ can do more than above…

Read More Read More

Linking

Linking

Linking Compiler Drivers When you run gcc -O2 -g -o p main.c swap.c ,These things happen First the C preprocessor translate main.cpp into main.i main.cpp—->(cpp)—->main.i cpp main.c /tmp/main.i Then main.i was compiled by C Compiler (cc1) into main.s main.i—->(cc1)—->main.s cc1 /tmp/main.i main.c -O2 -o /tmp/main.s Then the driver runs the assembler(as) and create a relocatable object file main.o main.s—->(as)—->main.o as -o /tmp/main.o /tmp/main.s Same things are done for swap.c Finally it runs the linker(ld) which combines main.o and swap.o and…

Read More Read More