自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

keep coding

小白的学习记录

  • 博客(133)
  • 资源 (1)
  • 收藏
  • 关注

原创 C++和C语言函数互相调用

C++中调用C函数// xx.hextern int fun(); // 声明fun// xx.cint fun() {} // 定义fun// xx.cppextern "C"{ #include "xx.h"}fun(); // 使用funC中调用C++函数// xx.hextern "C"{ int fun();}// xx.cppint fun() {} // 定义fun// xx.cextern int fun(); // 声明funfun();

2020-06-21 16:07:30 370

原创 多文档编辑器--(3)菜单项的功能

在前面两节中,实现了界面的设计(菜单项)和子窗口类的实现,下一步就是实现菜单项的功能,就是把菜单项和子窗口类的成员函数关联起来。1. 项目文件2. mainwindow.h 头文件#ifndef MAINWINDOW_H#define MAINWINDOW_H#include "mdichild.h"#include <QMainWindow>#include &l...

2020-03-04 10:37:30 587

原创 多文档编辑器--(2)创建子窗口类

为了更好的在MDI Area中添加子窗口,那就子类化子窗口,它继承自 QTexiEdit 类。1. 添加新文件选择新建一个 类类名为: MdiChild,继承自 QTextEdit。2. 子窗口类的头文件#ifndef MDICHILD_H#define MDICHILD_H#include <QWidget> // 头文件包含#include &l...

2020-03-03 22:32:12 411

原创 多文档编辑器--(1)界面设计

刚刚接触 Qt,了解了一些基本操作之后准备动手做一个小小的项目。以实践为导向来学习Qt,详细记录学习步骤。1.新建项目新建 Qt Widgets Application类信息选择如下,基类选择QMainWindow,勾选“创建页面”。2.设计界面(编辑 .ui 文件)添加 “菜单” 和 “菜单项(action)”。在centralWidget中拖入MDI Area.最终,...

2020-03-03 18:15:51 500

原创 31.创建文件系统 file system

在 MBR、EBR、OBR的区别和联系 博文中,介绍了硬盘是如何分区的。再次把硬盘的分区图贴到下面。每一个分区可以有一个文件系统,不同的分区可以有不同的文件系统。仿照Linux中的ext2文件系统来创建文件系统。在一个分区中,先是引导块,然后是超级块,超级块是操作系统元信息的元信息。操作系统的元信息包括:inode 位图,inode 数组,空闲块位图,根目录等。空闲块就是用来创建文...

2020-02-18 20:54:23 365

原创 30. 硬盘驱动

一般的主板上有两个硬盘通道,叫做 ata 通道 或 ide 通道。第一个 ide 通道的中断信号挂在 8259A 的 IRQ14 上, 第二个挂在 IRQ15 上。一个通道可以挂两块硬盘,对,两块硬盘共用一个中断接口。每块硬盘又可以分区。分为主分区和逻辑分区。硬盘驱动程序包括,硬盘的初始化,硬盘的读操作、写操作。先定义数据结构/* 分区结构 */struct partition {...

2020-02-15 18:28:14 597

原创 MBR、EBR、OBR的区别和联系

先看图:一块硬盘,最开始只能实现4个分区,也就是4个主分区。后来的发展,4个分区不够用了,可以有一个分区作为扩展分区,用它来作为总扩展分区,里面可以分成很多个子扩展分区,每个子扩展分区在逻辑上看相当于一块硬盘。一块硬盘最开始的一个扇区作为MBR,MBR 的 512 字节包括 464 字节+ 64 字节的分区表 + 2 字节的魔数0x55aa。接下来就是各个分区了,各个分区开始的扇区是 O...

2020-02-15 18:17:59 2906 1

原创 29.实现malloc & free

结合前几节的内容,实现系统调用malloc 和 free。根据系统调用的步骤:(1)封装函数malloc & free(2)在函数中调用宏 _syscall1(),在宏中就执行int 0x80 中断进入内核态。(3)在syscall_table 数组中添加函数sys_malloc 和 函数 sys_free. 这样在中断处理子程序中就会跳转到 sys_malloc 和 sys_...

2020-02-13 16:31:36 210

原创 28.实现sys_free

无论在之前的内存管理中(实现一页的分配),还是上次的sys_malloc 中,都没有实现内存的回收机制。本次就来实现内存的回收,包括页内存的回收和回收sys_malloc申请的小内存。1. 实现 mfree_page 回收多个页框回收页框包含三步:(1)回收物理内存池——物理内存池的位图相应位清零(2)回收虚拟内存池——虚拟内存池的位图相应位清零(3)去掉页表中虚拟地址和物理地址的映射...

2020-02-13 15:18:08 239

原创 27.实现sys_malloc

在之前内存管理中,只是实现了页的申请,也就是说要申请内存,最小的单位也是1页即4k。这节来实现不同规格的内存分配,当然还是在之前页的申请的基础上来完成。1. arenaarena是提供内存分配的数据结构,包含两个部分,一部分是元信息,另一部分是内存块。arena可以是一个页框,页可以是多个页框。对于小于1024字节的内存申请,arena就是一个页,在这一个页中除去元信息,剩下的空间就平均的...

2020-02-13 12:43:06 334

原创 26.实现printf

1.printf是什么?printf是c语言的标准输出函数,原型是int printf(const char *format, …);其中format 是格式化字符串,其中就包含“%类型字符”.“…”是可变参数,参数不固定。printf 由两个函数封装而成,一个是 vsprintf ,另一个是 write。vsprintf 负责把 format 中的%d、%s、%c……给替换成真正...

2020-02-12 21:47:07 623

原创 25.实现系统调用syscall

原理:系统调用就是用户程序调用操作系统提供的函数,那么就需要从3特权级变化到0特权级。仿照Linux中的系统调用,用中断的方式来实现特权级的变化,进而实现系统调用。并不是一个系统调用就占用一个中断号,而是所有的系统调用都使用一个中断号,就是0x80 。通过eax的值来确定具体是哪个系统调用。实现的步骤:修改中断描述符表IDT,添加0x80号中断的描述符。建立一个系统调用的子功能表sy...

2020-02-12 15:48:22 781

转载 代码段之间转移时的特权级检查

https://www.cnblogs.com/ay-a/p/9141911.html

2020-01-11 10:09:58 132

原创 24.键盘输入缓冲

上一节实现了键盘驱动程序,每按一个键,都打印出来。本节实现一个环形缓冲区,来作为键盘输入的缓冲。缓冲区要有的功能:同一时刻只能被一个生产者或消费者使用(互斥);–锁来实现缓冲区满时,生产者不能往缓冲区添加数据;缓冲区空时,消费者不能从缓冲区取数据。ioqueue.h#ifndef __DEVICE_IOQUEUE_H#define __DEVICE_IOQUEUE_H#inc...

2019-12-20 10:10:10 773

原创 23.键盘驱动程序

在上一篇博文的基础上来修改键盘的驱动。只修改 keyboard.c(1)添加一些宏定义,(2)修改中断处理函数。其它不变。功能:功能有限,只能处理主键盘区的字符,只能和 Ctrl、Caps、Shift 组合。#include "keyboard.h"#include "../lib/kernel/print.h"#include "../kernel/my_interrupt.h"#...

2019-12-19 21:03:23 387

原创 22.简单的键盘中断测试

1. 硬件连接先看一下硬件的连接:键盘里有个 8048 芯片,当按下某个按键时, 8048 就把这个键对应的数值发送给 8042 ,8042就知道是哪个键被按下了,就会给 8259A 发送中断。一个按键被按下,产生的编码叫通码(makecode),断开时叫断码(breakcode)。按键有 3 种状态,“按下”、“按下保持”、“弹起”。有好几种键盘扫描码,需要一个“中间件”来隐藏各套扫...

2019-12-19 19:08:30 715

原创 21.用锁实现终端输出

本文就是利用上一篇博文的 锁 ,来实现终端输出,避免产生竞争条件。新建一个文件 console.c。console.c#include "console.h"#include "../lib/kernel/print.h"#include "../lib/std_int.h"#include "../thread/sync.h"#include "../thread/thread.h...

2019-12-19 16:19:07 159

原创 20.实现同步机制--锁

上一篇 博文中 运行了 3 个线程(主线程、k_thread_a、k_thread_b ),运行一段时间就会出现异常,这是由于产生了竞争条件。有 2 种竞争条件:(1)对显存未实现互斥访问。(2)对“光标寄存器”未实现互斥访问。1. 相关概念公共资源所有任务共享的一套资源。临界区各个任务访问公共资源的临界代码,临界区是指令,不是受访的静态公共资源。互斥某一时刻,公共资源...

2019-12-19 16:08:49 131

原创 19.实现线程调度

接前面几篇博文,在 17 在内核空间实现了线程, 18 实现了双向链表的数据结构。那么继续实现线程调度。操作系统是中断驱动的,线程的调度也是和中断息息相关的。首先是 PCB 的继续完善。thread.h 中添加/* 进程或线程的pcb,程序控制块 */struct task_struct { uint32_t* self_kstack; // 各内核线程都用自己的内核栈 e...

2019-12-18 16:17:56 249

原创 18.实现双向链表

本文为实现双向链表,为以后的 就绪队列、全部任务队列准备数据结构。一共包含两个文件,放在 /lib/kernel 目录下。list.h#ifndef __LIB_KERNEL_LIST_H#define __LIB_KERNEL_LIST_H#define NULL ((void*)0)#define bool int#define true 1#define false 0...

2019-12-18 14:42:34 157

原创 17.在内核空间实现线程

1. 实现线程有两种方法一种是在用户进程中实现线程,另一种是在内核空间实现线程。各自优缺点:(1)在用户进程实现线程线程的调度算法由用户进程自己实现,不同进程可以不同,更加灵活。不用陷入内核态即可完成线程的切换某个线程出现阻塞,操作系统就认为i是整个进程出现阻塞,会将整个进程挂起。操作系统调度的调度单元是整个进程。提速并没有很大的提高。(2)在内核空间实现线程一个线程出现...

2019-12-17 15:49:42 542

原创 16.内存管理系统-在虚拟、物理内存池中申请内存并修改页表使其映射

利用上一节的位图,来实现内存管理系统。内存管理本质上就是修改页表项。位图的作用是用来申请和释放内存时用的。1. 内存池的规划无论是内核还是用户进程,最终都要运行在物理内存上,所以物理内存分成两个内存池:用户物理内存池和内核物理内存池。在分页机制下程序的地址都是虚拟地址,虚拟地址的范围取决于地址总线的长度,咱们32位环境下,虚拟地址的空间是 4GB。每个任务都有自己的 4GB虚拟地址空间...

2019-12-16 12:29:17 434

原创 15. C语言实现位图 bitmap

1. 位图是什么?位图是一种资源管理的方式,按位bit与资源一对一的对应关系。位图中的每一位将于内存中的每一页一一对应。一个位有 2 种状态,即 0 和 1 ,用位图中的每一个位来表示实际物理内存的 4KB(一页) 。如果某位为 0 ,表示该位对应的页未分配。反之,某位为 1 ,表示该位对应的页已分配。2. 实现位图实现位图,用到两个文件,bitmap.c 和 bitmap.h。b...

2019-12-13 10:01:27 2056

原创 14.ASSERT断言的实现 + Makefile

断言 ASSERT 是用宏来实现的。原理是判断传给 ASSERT 的表达式是否正确。参看博客《断言(assert)的用法》https://blog.csdn.net/jiaruitao777/article/details/103509909assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终...

2019-12-12 15:38:50 583 3

转载 断言(assert)的用法

我一直以为assert仅仅是个报错函数,事实上,它居然是个宏,并且作用并非“报错”。在经过对其进行一定了解之后,对其作用及用法有了一定的了解,assert()的用法像是一种“契约式编程”,在我的理解中,其表达的意思就是,程序在我的假设条件下,能够正常良好的运作,其实就相当于一个if语句:if(假设成立){ 程序正常运行;}else{ 报错&&终止程...

2019-12-12 15:34:31 242

转载 跟我一起写Makefile——精心整理版

跟我一起写Makefile——精心整理版https://seisman.github.io/how-to-write-makefile/overview.html

2019-12-12 09:06:56 352

原创 13.设置8253,提高时钟中断的频率

上一篇博文《12.创建IDT、中断处理程序,初始化8259A,中断测试》中,检测的是IRQ0的中断,就是时钟中断,这个中断时8253提供的,默认时18.206Hz,我们这次通过设置 8253 来把时钟中断的频率提高到 100 Hz。CLK是 8253 的时钟输入频率。8253 有3个独立的计数器。往控制字寄存器写入控制字来设置 8253 的工作方式。往计数端口写入计数初值。8253...

2019-12-11 21:30:05 1451

原创 12.创建IDT、中断处理程序,初始化8259A,中断测试

0. 中断那些事儿中断分类外部中断1.1 可屏蔽中断(INTR)1.2 不可屏蔽中断(NMI)内部中断2.1 软中断2.2 异常一共0~255,256个中断。这个0~255就是中断向量号。处理器就是根据中断向量号来定位中断处理程序的。操作系统是中断驱动的,在实模式下有中断向量表(IVT),中断发生后找到中断处理程序的入口;在实模式下有中断描述符表(IDT),中断发生后根据...

2019-12-11 16:05:15 1259

原创 11.完善内核-打印整数

接前两篇博客.print.S中添加:global put_intput_int: pushad mov ebp, esp mov eax, [ebp+4*9] ; call的返回地址占4字节+pushad的8个4字节 mov edx, eax mov edi, 7 ; 指定在put_int_buf...

2019-12-08 20:49:33 185

原创 10.完善内核-实现打印字符串

上一节通过控制显存实现了打印单个字符,这一节调用上一节的函数来实现打印字符串。在print.S中添加:global put_str ;全局声明put_str: push ebx push ecx ;备份ebx,ecx xor ecx, ecx mov ebx, [esp + 12] ;从栈中取出字符串的地址.goon: mov cl, [ebx] ;挨个读出字符 c...

2019-12-08 20:18:39 258

原创 9.完善内核-实现自己的打印函数

经过前面 8 个博客,已经把执行内核之前的准备工作完成了,接下来跳转到内核执行。本次的打印函数就是控制显卡来完成的,就像之前 MBR 读硬盘,加载loader、loader.S 读硬盘加载内核到内存一样,控制显卡就是控制显卡中相关的寄存器。对于显卡中寄存器的控制,涉及到端口,还是直接使用汇编来实现。步骤:备份寄存器现场获取光标位置获取待打印字符判断字符是否为控制字符,回车、换行、退...

2019-12-08 19:46:38 291

原创 Ubuntu16.04_x64的gcc 编译32位 elf 文件

原来的格式源文件为 main.c若直接使用gcc 编译文件,编译出的是 ELF64 格式的。用 readelf -e 文件名,即可查看文件的ELF的信息。由上图可以看出,直接使用 gcc 编译、链接出来的elf 文件,class 是ELF64,machine是 Advanced Micro Devices X86-64。而我们需要的是ELF32格式的,而且是要运行在intel 8038...

2019-12-06 12:11:38 1962

原创 8.加载内核并初始化内核

1. 用 C 语言写内核int main(void){ while(1); return 0;}最最简单、没有实用的内核。咱们的目的是加载内核并初始化内核。所以内核不需要太复杂。用 gcc 编译器:gcc -c -o main.o main.c //编译汇编到目标代码,不进行链接。ld 进行链接程序,指定可执行程序的起始虚拟地址。ld main.o -Ttext 0x...

2019-12-06 11:12:23 324

原创 7.构建页表,启用分页机制

关于分页的原因,分页机制的原理就不赘述了。0.一些问题问:前面已经把内存分段了,难道直接舍弃,采用分页嘛?答:要兼容,不舍弃。分段用 [段基址:偏移地址]得到一个线性地址,得到的线性地址再经过分页机制的转换,才得到真正的物理地址。才把这个物理地址送到地址线去访问真实的物理内存。分页机制是建立在分段机制之上的。段部件的作用是根据段基址和偏移地址得到一个线性地址。在没有启用分页机制的情况下...

2019-12-05 11:08:39 415

原创 6.检测物理内存的容量

操作系统是管理硬件的大管家,所以它要知道有哪些硬件资源啊。比如要检测内存,知道内存的容量。1.学习 Linux 中的获取内存的方法学习 Linux 中的获取内存的方法,调用 BIOS 中断 0x15 来实现内存容量的检测。0x15 中断一共有 3 个子功能:EAX=0xe820 ;遍历主机上全部内存AX=0xe801 ;分别检测低 15MB 和 16MB~4GB 的内存,最大支持 ...

2019-12-04 15:14:38 917 1

原创 5.从实模式进入保护模式

本文接上一篇博文,在 loader.S中干点正事儿。进入保护模式。1.什么是保护模式?最经典的 8086CPU 是只有实模式的。实模式下有很多的不足,所以有了保护模式。实模式的缺点:操作系统和用户程序处于同一特权级。用户程序所引用的地址都是指向真实的物理地址。用户程序可以自行修改段基址,可以访问所有内存。访问超过 64KB 的内存区域要切换段基址。一次只能运行一个程序。共 20...

2019-12-02 20:18:43 806

原创 4.实现MBR控制显示器,读硬盘,加载loader的功能

前面博文 编写主引导记录MBR 中的MBR程序没有实际意义,只是单纯的在屏幕显示几个字符,而且不是自己直接操作显卡,是调用了BIOS 的中断。1. MBR 直接控制屏幕输出本文先来实现 MBR 通过往显存中放入数据来控制屏幕的输出。少废话,先上代码。%include "boot.inc" ;包含头文件SECTION MBR vstart=0x7c00 ; 定义一个节,虚拟地址0x7c0...

2019-11-30 11:09:26 1716

原创 3.计算机上电 到 BIOS 再到 MBR的过程详解

本文详细分析了计算机上电到BIOS 再到MBR的过程,包括寄存器的改变,物理地址的改变,各部分的作用等等。

2019-11-28 14:11:45 412

原创 2.编写主引导记录MBR

这一篇继续编写MBR,但是开发环境有一点的小改动,是在Linux环境下的bochs中进行测试我们写好的MBR好了,我们马上开始。1. 首先先在Ubuntu中安装 bochs2.9.6。sudo apt-get update //先升级一下,以免后续的安...

2019-11-28 09:57:08 501

原创 1.自己写操作系统--开发环境的搭建与第1个操作系统(完全可复现)

本文为操作系统的实践的第一部分,包括环境的搭建,和制作第一个操作系统并运行起来。完全可复现。

2019-11-21 19:15:36 2677 1

12.提高时钟中断的频率 -改进目录结构.rar

>boot.inc ————mbr.S要用到的一些宏定义 >mbr.S ————往显存显示一些字符,把loader.S读到内存执行 >loader.S————检测内存容量、构建GDT、进入保护模式、加载内核、创建页表、开启分页、跳到0xc0001500执行 >timer.S————设置 8253 工作模式,提高时钟中断的频率 >timer.h————声明 timer.S 中的函数 >8259A.S————两个函数:设置8259A的pic_init 和 开启中断的set_if >8259A.h————声明 8259A.S 中的函数 >kernel.S————1)中断处理程序 和 2)加载 idt到IDTR寄存器的函数lodidt >kernel.h————lodidt函数的声明 >my_interrupt.S————创建中断描述符 >my_interrupt.h————声明idt_inti函数 >main.c————调用 idt_inti 来创建idt、初始化8259A、开启中断;调用timer.S函数来提高时钟中断频率 >print.S————控制显存来往屏幕打印字符、数字、字符串 >print.h————print.S中的函数的声明 >std_int.h————一些整型的别名

2019-12-11

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除