- 博客(36)
- 收藏
- 关注
原创 Day24 窗口操作
是阻塞等待,就是当fifo为空时,本任务会先休眠等待直到fifo中有内容。当定时器超时时,会产生128这个值(键盘编码不会产生128)。还需要在定时器结构体中增加一个标记,标识该定时器是否需要在应用程序结束时结束自动取消。当前存在的一个问题是,如果应用程序被取消了,那么定时器还在按照频率触发。
2025-09-19 22:22:10
206
原创 Day23 图形处理相关
导致winhelo2.hrb的二进制文件中存在很多00。但是又无法直接调用memman_alloc函数,因为通过memman_alloc获取的函数并不位于应用程序的数据段范围内,应用程序进行读写的话会产生异常。,系统就会为malloc准备40KB的内存空间。当指定了malloc所需的内存大小后,这个数值会和栈的数值相加,写入.hrb文件的最开头4个字节中;同时,malloc用的内存空间在数据段的开始位置,被保存在.hrb文件的0x0020处。由于在winhelo2.c文件中存在一个。
2025-09-15 09:07:10
203
原创 Day22 用C语言编译应用程序
也就是说,0x000c位置的内容表示栈指针,调用api_putstr0的时候所传入的参数s就会放在0x000c的内容所代表的内存地址处。0x0000位置存放的是应用程序启动后数据段的大小,bim2hrb会自动将该内容调整为4KB的倍数,所以0x0000位置的字节必定是00。一个普通文件的0x0000位置却很小可能是00,但是却有可能是某个字母,所以将“Hari”字符放在文件的0x0004位置可以提高访问的安全性。但是还忽略了一点,应用程序的地址的CALL并不是任意的,只能CALL设置好的地址。
2025-09-13 21:25:47
792
原创 Day21 保护操作系统
由于把麻烦的栈切换全部由CPU处理了,因此_asm_inthandler20,_asm_inthandler21,_asm_inthandler2c等系列的函数也都需要恢复原来的样子。类似的需要修改每一个中断的汇编函数(_asm_inthandler20,_asm_inthandler21等),因为中断产生后会调用_inthandler20等操作系统内部的C语言函数,因此也需要对DS和SS进程切换。x86存在一个功能,在段定义的地方,如果将访问权限加上0x60,就可以将段设置为应用程序用。
2025-09-06 16:52:36
895
原创 Day20 API
使用INT指令调用函数的时候,会被视作中断来处理,因此在被调用的函数内部,无法使用RET进行返回,需要替换为IRETD指令。另外,当INT调用的时候,CPU会自动执行CLI指令来禁止中断请求,为了防止这种情况,在应用函数_asm_cons_putchar的开头首先执行STI用来取消禁止中断。在C语言中,goto语句和函数调用的处理方式完全不同,但是在汇编语言中CALL指令和JMP指令本质上差不多,只是在执行CALL时,会自动将函数执行结束后的返回地址PUSH到栈中。如果找到文件则返回1,未找到则返回0。
2025-09-01 22:22:06
741
原创 Day19 应用程序
FAT中的内容在磁盘映像中是被压缩过的。根据FAT读取文件的过程是一个顺藤摸瓜接力的过程,如果其中一环读取错误,就导致该文件读取是错乱的。Windows中对于大于512字节的文件,有时候并不是存入连续的扇区,不过是完全可以追溯的。存在一个FAT(file allocation table),位于0柱面,0磁头,2扇区开始的9个扇区中,在磁盘映像中相当于0x000200 ~ 0x0013ff区域。中实现dir命令的时候,提到每个文件的信息都存储在一个32字节的结构体(struct FILEINFO )中。
2025-08-31 08:46:24
947
原创 Day18 dir命令
从磁盘映像的0x4200就开始存放文件haribote.sys(见3.5章节),因此文件信息,最多存放224个。在harib15c中,当光标到达最后一行的时候,回车键就无法换行了,因为下面没有更多的行。取消在sheet_back上显示的内存使用情况,期望查看的时候,通过mem查看。查看hariboot.img磁盘映像,自0x2600开始,每个文件的信息占用32字节。dir命令的作用就是现实磁盘中的内容,类似于Linux系统中的。在3.4章节中,已经从磁盘中读了10个柱面的内容,将放在了。
2025-08-28 08:56:01
349
原创 Day17 命令行窗口
后续(harib13b及之后)为了将HLT时间让出来,让给task_b工作,于是就编写了task_sleep函数,当被调用时传入task地址,会将该task移出tasks数组,并farjmp到其他task。为了防止定时器的fifo32_put和键盘的fifo32_put冲突,对键盘的数据加上了256,并在task_cons中根据get到的值以+256判断其内容。因此,此时期望实现:一般情况下让任务休眠,但是当所有level都没有任何task存在时,就需要HLT了。将命令行窗口制作为一个单独的task,
2025-08-25 08:39:49
863
原创 Day16 多任务(2)
类似图中所示,最上层的level0中只要存在一个task,则完全忽略level1和level2中的task,只在level0的任务中进行切换。由于任务A中主要做鼠标,键盘,定时器的处理操作(打印),所以当没有这些动作时,任务A是空闲的(HLT),但是任务B却一直在工作。增加一个level结构体作为一类task的集合,本level中的task在活动中时,其他level的task就不应该被调度到。增加新的任务,最终使共4个任务,并分别命名为task_a,task_b0,task_b1,task_b2。
2025-08-17 18:45:34
392
原创 Day15 多任务(1)
如果JMP指令所指定的目标地址段不是可执行的代码,而是TSS,此时CPU就不会去做改写EIP和CS的操作,而是将该指令理解为一个任务切换。为了运行下一个程序,CPU会把所有寄存器的值从内存中读取出来(当然上一个程序被写入的地址,不同于下一程序读取的地址),这样就完成了一次任务切换。从翻译为的机器语言看,普通的far-JMP和任务切换的far-JMP是没有差别的。这里把cs设置为GDT的2号,其他寄存器都设置为GDT的1号,这样的设置与asmhead.c中是一样的,即与asmhead.c使用了相同的地址段。
2025-08-10 11:26:51
958
原创 Day14 高分辨率及键盘输入
在次之前,一直使用的是320*200的分辨率。如果期望修改为更大的,可以参考下图中VBE(Video Electronics Standards Association BIOS extension,VESA协会的BIOS扩展)所定义的画面模式号码,将以下数字加上0x4000并赋值给BX。大多数显卡都支持VBE。所获取的画面信息存储在[ES:DI]开始的256字节中。实现打字的效果,并使用退格键(backspace)。根据这个表就可以在按下键盘的时候显示键上的字符。
2025-08-01 09:04:40
461
原创 Day13 定时器(2)
最初using的作用是对运行中的定时器进行计数,当时还存在一个timers[]数组,using帮助记录timers[]已经被使用到哪一个位置。当有了哨兵后,using就不会等于0。每次即将到达之前都会修改时刻,因此无论如何不会到达它的超时。它一直在最后位置,只是一个附带物,一个留守者,称其为“哨兵”。在TIMER结构体中添加一个next_timer指针变量,用于指向链表中本TIMER的下一个TIMER类型变量。随之,将鼠标、键盘和定时器使用的FIFO缓冲区汇总为一个FIFO32缓冲区,这样可以节约性能。
2025-07-29 09:08:32
429
原创 Day12 定时器(1)
因此,程序只需要按照自己的步调节奏处理自己的事情就好了,至于经过了多长时间,只需要在中断处理程序中数一数定时器产生中断的次数。不同的cpu,执行指令的时钟周期不同,一个时钟周期是多久的时间取决于cpu的主频。类似键盘的处理,需要在naskfunc.nas中添加对inthandler20的调用,以及在dsctbl.c中将中断处理程序注册到IDT中。当前的中断函数中,做的处理太多,严重影响系统的运行速度。由于设定了中断产生的频率为100Hz,因此计数累加的速度期望为1s增加100。函数中将计数值打印出来。
2025-07-25 13:36:55
925
原创 Day11 制作窗口
函数中,图层移动时会导致下面的图层露出,因此需要从下面的图层开始刷新。在图层所移动到的目标位置处,比新移来的图层低的图层没有什么变化,只是需要隐藏一部分,所以只需要刷新移动图层和它上面的图层。鼠标的闪烁显现是由于一会描绘一会消除产生的。在移动前的地方,只针对上层图层移走后而露出的下层图层进行重绘就行了,在移动目的地处仅重绘了一张移动过去的图层。如图,期望刷新图层1的时候,参照map的内容刷新,就不必担心图层1和图层2的重叠部分了。函数中,同样的思路,针对个别不需要自下而上全部刷新的图层,仅刷新其局部。
2025-06-30 22:50:12
603
原创 Day10 叠加处理
将bootpack.c中的内存管理内存整理到memory.c中,并添加以0x1000(4K字节)为单位的内存申请和释放函数。表达的含义,即尽管只刷新涂层的一部分,但是仍要对所有图层的所有像素执行if判断。每个字占用8*16个像素,可以只刷新所有字的像素。函数中,找寻未使用的图层,标记为正在使用,并且对height字段设置为-1,表示该图层并不是被显示的对象。按照harib07b的策略,鼠标指针占用256个像素,鼠标稍微移动,就需要刷新320。,显示的效果如图,不会导致鼠标走过的地方就残留轨迹了。
2025-06-29 10:59:55
301
原创 Day9 内存管理
操作系统使用过程中存在一种情况:假设内存大小是128M,App程序A暂时100KB,画面控制用到1.2M等类似这种情况,操作系统需要分配一段内存,用完之后就不再需要,这种事会频繁发生。观察机器语言的流程会发现,9成以上的时间会耗费在循环上,加入cache后,从第二次循环开始,需要读取访问的地址的数据就会被放置在cache中;作用主要是调查从start到end的地址范围中,每4KB内存,可以使用的内存的末尾地址。的这种操作,每次循环需要对变量i赋值,即对i的内存地址写入,此时就会写入到cache中。
2025-06-16 08:51:06
596
原创 Day8 鼠标控制与32位模式切换
因此,在bootpack.c的HariMain里,应该在进行调色板(palette)的初始化以及画面的准备之前,先重新创建GDT和IDT,初始化IPC,并执行io_sti();这里的 virtual 和 real 的区别在与计算内存地址时,是使用段寄存器的值直接指定一部分,还是通过GDT使用段寄存器的值指定并非实际存在的地址号码。如果不在这个范围,就被舍弃。最初的电脑,CPU只有16bits模式,所以内存最大只有1MB,后来为了兼容旧版的操作系统,在激活指令之前,电路被限制为只能使用1MB内存。
2025-04-28 09:08:57
1253
原创 Day7 FIFO与鼠标控制
但是当前还存在一个有问题的现象,例如,右Ctrl键会产生两个字节的键码,按下时为“E0 1D”,松开时为“E0 9D”,在这种情况下,因为键盘的内部电路,一次只能发送一个字节,所以一次按下就会产生两次中断,第一次中断发送E0,第二次发送1D。所谓不产生鼠标中断,就是说即使鼠标发来数据,CPU也不会接收,所以,处于初期状态的鼠标,无论怎么操作,都不会有反应。所谓中断处理,就是打断CPU正在手头的工作,加塞处理另一个事情,所以必须完成的干净利索,而且中断处理进行期间,不再接受其他的中断。
2025-04-07 08:31:52
1116
原创 Day06 分割编译与中断处理
段的上限是4GB字节,需要使用一个32bits的数字表示。PIC的寄存器都是8位寄存器,IMR是“interrupt mask register”(中断屏蔽寄存器),8位分别对应8路IRQ(interrupt request,中断请求)信号,如果IMR的某一个bit为1,则这一路IRQ信号被屏蔽,PIC就忽视这一路信号。这个函数所做的动作主要是,将寄存器的值保存在栈里,然后将DS和ES调整到与SS相等,再调用_inthandler21,返回以后,将所有寄存器的值再返回到原来的值,最后执行IRETD。
2025-04-04 22:03:27
1088
原创 Day5 结构体、文字显示与GDT/IDT初始化
使用OSASK字体数据(记录在hankaku.txt文件中),并使用专用工具makefont.exe将hankaku.txt文件制作成一个bin文件,接着使用bin2obj.exe工具使其生成目标文件,就可以连接到可执行文件中。各个设备有变化时就会产生中断,中断发生后,CPU暂时停止正在处理的任务,并做好接下来能够继续处理的准备,转而执行中断程序。段寄存器的低3bits不允许使用,因此段号可以是0 ~ 8191之间的数字,因此最多可以设置8192个段,存储这么多段的信息总共需要。
2025-03-16 22:54:27
991
原创 Day4 C语言与画面显示练习
在两种指令中,为了区别不同的设备,也需要使用设备的号码(称为“port”,意为港口),可以理解为CPU与设备交换信号的行为类似于船舶的出港和进港。调色板(palette):用8bits的颜色名来表示24bits种类的颜色,例如2号(8bits)颜色就是#ff0000(亮红),3号颜色就是#00ff0(亮绿)。在当前的画面模式中,画面上有320*200(=64000)个像素点,假设左上点的坐标为(0,0),则右下角的坐标为(319,199)。CLI屏蔽中断,就是将中断标志置为0的指令,即忽略中断请求;
2025-03-08 22:08:50
1201
原创 Day3 进入32位模式并导入C语言
并没有特殊的含义,只是由于启动区加载到0x7c00 ~ 0x7dff区域,所以0x07e00 ~ 0x9fbf之间没有特别用途,操作系统可以随意使用,因此就选择了0x8200之后的区域。它只是将所有的目标文件链接在一起组成了一个完整的机器语言文件,为了能实际使用,还需要针对不同操作系统的要求做必要的加工,例如用于识别的文件头,压缩等。当使用段寄存器时,以。CPU的16位模式和32位模式中,机器语言的命令代码不同,同样的机器语言,解释方法也不同,所以16位模式的机器语言在32位模式下无法运行,反之亦然。
2025-02-28 08:42:15
745
原创 Day2 汇编语言学习与Makefile入门
ipl.bin : ipl.nas Makefile”表示,如果期望制作一个ipl.bin文件,就需要先检查一下ipl.nas和Makefile是否准备好,如果存在,make工具就会自动执行下一行命令。此外,default是Makefile中的一个关键字,意思是如果只执行make命令,其后不跟任何选项参数,则默认执行这一句,所以在helloos5文件夹下,cmd执行。这个脚本的功能是将所输出的ipl.bin写入磁盘映像img的开头,组成一个新的完整的磁盘映像文件helloos.img。
2025-02-13 09:09:27
1009
原创 day01 从计算机结构到汇编程序入门
书中例程的玩法一般是,将img操作系统镜像和一些辅助文件(比如,编译脚本,运行脚本)放置在一个文件夹下,这些脚本中的内容都是以相对路径编辑的,再将该文件夹放置在tolset目录下。表示启动区,一般是软盘的第一个扇区。由于启动区只有512字节,操作系统无法直接放在里边,因此一般将操作系统的引导程序放在启动区里。否则,则认为该软盘中没有所需的启动程序,就会上报一个不能启动的错误。今天开始记录看的《30天自制操作系统》这本书,书的名字显示这书不是一本好书,不过据说还不错,我就记录一下看书和实验的过程。
2025-01-20 08:58:37
182
原创 《code》 24th “低级语言与高级语言”
如果不经压缩,一帧数据是640x480,每个像素为24bits真彩色,每一帧则是921,600字节,如果播放速度为30帧/秒,则每秒需要存储空间为27,648,000字节,一部两小时的电影大概199,065,600,000字节(约200GB)。如果要为新的机器写一个汇编器,新的汇编器(本质上是一个程序)可以在已有的计算机上的使用汇编语言编写,并利用已有机器上的汇编器对其汇编,这种方式称为交叉汇编(cross-assembler),即利用计算机A的汇编器对运行在计算机B上的程序进行汇编。
2025-01-18 09:39:11
847
原创 《code》 23th “定点数和浮点数”
例如,当e为0时,科学计数法的指数为-127。为了防止有的数字过大或过小导致预留空间不足,一般使用科学计数法(scientific notation),它把每个数表示成有效位(或有效数)与10的幂乘积的形式。对于小数,基于二进制的存储和标志方式被称为定点格式(fixed-point format),所谓的定点是指小数点的位置总是在数字的特定位置。如果某个数不是以整数为系数的代数方程的解,那么这个数就是超越数(transcendental),所有超越数都是无理数,但反之不成立,pi和e就是典型的超越数。
2025-01-12 20:10:28
995
原创 《code》 22th “操作系统”
在启动计算机时,需要把CP/M加载到内存中。如果程序比磁盘的扇区大,存放这个程序就会用到多个扇区,但是磁盘上某些扇区被占用,某些扇区空闲,可能在磁盘上难以找到一块完整的连续的足够大的扇区存放程序,所以如果期望存储一个较大的程序(大于每个扇区的size)就需要手工记录。为了解决磁盘容量越来越大,难以查找的问题,DOS引入了层次文件系统(hierarchical file system),目录区同样存储在磁盘的特定区域,不同的是有些文件本身也是目录(这些文件包含其他文件,并且所包含的文件中仍旧可能存在目录)。
2025-01-11 19:23:04
809
原创 《code》 21th “总线”
一台完整的计算机会按照功能将各部件分别安装在几个电路板上,这些电路板之间就通过总线(Bus)连接。总线可以认为是数字信号的集合,这些信号被提供给计算机上的每块电路板。地址信号:由微处理器产生,通常对RAM进行寻址,也可以用来对连接到计算机上的其他设备寻址;数据输出信号:由微处理器产生,用来把数据写入到RAM或其他设备;数据输入信号:由其他部分产生,由微处理器读取。通常是由RAM输出,也有其他部件对微处理器提供数据的输入;
2025-01-02 09:03:19
758
原创 《code》19th “两种典型的微处理器”
除了CF(进位标志位)和ZF(零标志位)外,8080还添加了3个其他的标志位(flag),包括SF(符号标志位),PF(奇偶标志位)和AF(辅助进位标志位)。由于8080芯片中有6个寄存器(如果假设累加器也算一个寄存器,8080将包含7个,在汇编代码的实现中看起来确实作用是相似的),因此它存在63个MOV指令用于将数据从一个寄存器移动到另一个寄存器(依然遵循左边是目的操作数,右边是源操作数)。对于LDA指令,它可以把单字节的操作数搬移到累加器中,该指令的最后直接跟的是操作数在RAM中的16位地址;
2024-12-28 16:27:59
1652
原创 《code》 18th “从算盘到芯片”
当存储器比较小时,就需要通过某些存储器地址控制其他介质来存取信息,这样就绕开了存储器的大小限制(例如,假设在存储器的某地址写入一个字节就在纸带上打一个孔,而从存储器中读出这个字节的时候就相当于在纸带上读取一个孔)。集成电路需要经过非常复杂的工艺流程,包括将硅片分层(大致为绝缘层,导体层,整流层和放大层),然后非常精确的掺入杂质,以及蚀刻不同的区域形成微小组件。书中在这中间还说了很多有趣的历史,“信息论”,“控制论”,“赛博朋克”的来源,“electronic brain (电脑)”的来源等。
2024-12-21 17:59:12
736
原创 《code》 17th “自动操作”
可以想到的一个方法是有另一个的RAM专门用于保存指令(本质也是二进制,不同二进制组合表示不同的人类语言指令),该指令RAM和存放待计算的数据的RAM有所存放的东西一一对应,即RAM。计算乘法是就可以用到“Jump If Not Zero”指令,同样是将乘法认为是一个数(其中一个乘数)的重复多次(另一个乘数)相加,使用非零跳转指令,可以再没跳转一次后将累加的次数(另一个乘数)递减1直到减为为0,则停止跳转。这四个指令中的零和进位指的是,使用该指令前最近的一条计算指令的输出是否为0和是否进位。
2024-12-18 08:55:56
897
原创 《code》 16th存储器组织
RAM阵列的存储容量可以用以下公式计算,其单位是由数据输入端决定的(每次可以输入多少数据,则单位就是多少)。例如,下图中输入输入端每次可以输入8bits(或1字节)的数据,地址输入有10bits,则该RAM可以保存1024x8bits的数据,或称为1024字节的数据。将该电路称为1024x8 RAM阵列。需要注意的是,根据最初11章引入的继电器的基本结构,每个继电器都需要与某个电源连接在一起,可以认为继电器有一个实际做功电源和一个控制电源,当然两者有时候也是同一个。
2024-12-04 22:36:16
1315
原创 《code》 14th “反馈与触发器”
如果计数器的输出连接灯泡,则0000 0000时灯泡为全灭,1111 1111时为全亮,从全灭到全部亮起总共需要经历255次跳变,从本次全灭到下次全灭则总共需要256次跳变。当保持位为1时,电路的输出与数据段相同(数据端1,Q为1;先看加法器,将八位加法器的低8bits输出传输至八位锁存器,“保存”开关控制时钟位,通过“来自锁存器”开关控制2-1选择器的输出是来自锁存器还是来自其他开关。由于在原则上,复位和置位应该是相反的,并且期望只有一个数据输入端,因此对两者设置同输入,并在之间加装反向器。
2024-12-01 19:34:29
1200
原创 《code》 13th “如何实现减法”
由于逻辑异或门的特点是“输入A为0则输出等同输入B,输出A为1则输出相反与输入B”,因此可以使用逻辑异或门,将取反作为公共的异或门输入A,将第二个操作数作为异或门的输入B。书中本章节最后,对于二进制补码,二进制负数之类的概念讲的确实清晰,值得看原书,但是对于补数的概念,感觉有点前后矛盾了,个人理解起来有点牵强,不过也可以接受。同样的,在十进制中,使用一串9减去减数得到的差就叫做对9的补数。但是在求对1的补数的时候好像根本不需要使用减法,只需对原来的操作数1变为0,0变为1,即取反码(inverse)。
2024-11-26 08:51:05
944
原创 《code》 12th chapter “二进制加法器”
如果使用同样规格的继电器制作一台加法器,该加法器的运算总的速度为:加法算数的位数*全加器硬件的速度。这被称为“行波进位”(ripple carry)。更快的加法器使用“前置进位”的电路来提高计算速度。当继电器后来被真空管替代,真空管后来又被晶体管替代。但搭建8位加法器仍旧需要144个晶体管(如果使用前置进位,则需要更多的晶体管)。
2024-11-23 12:26:11
1435
原创 《code》11th chapter “门”
理论上只需要四个开关就可以定义顾客中意的猫咪,其实就像代码中的那样:性别,是否生育,颜色组1,颜色组2(因为此时有四种颜色待选,所以需要两个开关才能完全表示)。现在回到选猫的问题,最开始说的,只需要两个开关就可以演示该猫的颜色,即可以认为两个开关控制四个灯的亮灭,即两个输入获得四个输出。显然,也类似开关的并联,闭合任一开关,都可以点亮灯泡。与门的符号不仅仅代表了两个串联的继电器,还暗示了上边的继电器与电源相连,并且两个继电器都接地。本书的每一章就是一个长长的章,中间没有分节,至少11章之前是的,有点难搞。
2024-11-22 08:53:17
788
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅