自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(92)
  • 资源 (1)
  • 收藏
  • 关注

原创 pipe

进程同步看一下上一节写的调用外部shell的方法。memset(final_path, 0, sizeof(final_path));int32_t pid = fork();if (pid){ while(1);}else{ make_clear_abs_path(argv[0], final_path); argv[0] = final_pa...

2018-05-19 17:41:51 519

原创 exec

exec在linux的bash shell中,执行外部命令时,该shell会fork一个子进程,这个子进程调用exec从磁盘上加载外部命令对应的程序。这是exec的一个应用。通过它的应用来看原理exec会把一个可执行文件的绝对路径作为参数,把当前正在运行的用户进程的进程体用该可执行文件的进程体替换,从而实现新进程的执行,而进程的pid是不变的。可以这样认为,exec并没有创建新的进程,只是...

2018-05-19 17:40:24 1679

原创 二十一. elf文件格式解析

elf文件格式我们的程序是通过gcc编译的,在linux下,gcc编译出来的可执行文件是elf格式的二进制文件。那么肯定要elf文件进行解析才能正确的得到进程可执行数据的位置。下面介绍一下elf格式的几个基本概念一个程序中最重要的部分是段和节,他们是真正的程序体,存储程序执行所需要的数据,程序中有很多段,常见的有代码段和数据段,段是由节组成的。多个节经过链接之后被合并成一个段。段和...

2018-05-19 17:39:27 1558

原创 shell1

路径解析转换路径有绝对路径和相对路径之分,在平常使用linux的过程中,我们在输入命令和参数的时候,往往使用的都是相对路径。相对路径是基于当前的工作路径的出的。当前工作路径 + 相对路径 = 绝对路径比如说当前工作路径为 /home/work 此时输入 ls file,那么file所在的绝对路径就是 /home/work/file 了。因为这个kernel比较简单,如果路径以根目录...

2018-05-19 17:38:28 223

原创 shell

fork的原理先通过下面这段代码简单的介绍一下fork这个函数,了解一下它的功能#include <unistd.h>#include <stdio.h>int main(){ int pid = fork(); if (pid == -1) return -1; if (pid) { ...

2018-05-19 17:37:46 173

原创 十八. 文件系统四(文件的读写与删除)

写入文件文件的数据都是记录在inode中的文件块中,在该文件系统的设计中,只用了12个直接块和一个间接块来存储文件,所以一个文件最大可以存放 140 * 512字节的数据。写文件的过程对文件块和扇区的分配过程,根据当前要写入的数据量大小,来判断是否需要分配新的数据块。如果12个直接块不够存储该数据,就分配间接块来存储,当所需的数据块分配好了之后,就会逐块的往硬盘上写入数据,知道所有的数据被...

2018-05-19 17:36:33 1005 2

原创 filesystem3

文件描述符在之前介绍的概念中,inode是用来表示一个文件的,用于描述文件的存储信息,文件的权限等。但这个inode结构是操作系统为自己的文件系统准备的数据结构,仅供其内部使用,与用户的关系不大,接下来要介绍的文件描述符才是用户能够使用的结构。在linux系统中,读写文件的本质是先通过文件的inode找到文件数据块的扇区地址,随后对这些扇区的数据进行读写,从而实现了文件的读写。对用户进...

2018-05-19 17:35:57 309

原创 filesystem2

在前面一节中介绍了文件系统的基本概念,接下来就要准备开始实现我们的文件系统,下面是为管理文件系统提供的几个基础数据结构。超级块的结构/* 超级块 */struct super_block{ uint32_t magic; // 用来标识文件系统类型,支持多文件系统的操作系统通过此标志来识别文件系统类型 uint32_t sec_cnt; ...

2018-05-19 17:35:20 200

原创 filesystem

磁盘的基础概念扇区:它是磁盘读写的基本单位。在我们个人的pc上,他的大小通常为512byte块:在windows中,称为簇。一个块由多个扇区组成,磁盘在进行读写数据的时候,不可能有一扇区的数据就读或写一次,而是等数据累计到一定量后,在统一进行读写,而这个数据量就叫块。在对磁盘进行格式化分区的时候可以选择块的大小,默认的是4kb。因为每次进行读写的数据量都是一块为单位,所以在磁盘上数据的存储...

2018-05-19 17:34:40 6604

原创 malloc&free

之前的内容中已经实现过内存分配的功能,但之前的内存管理模块中只是实现了内核空间的内存分配,而且每次分配的空间都是已页为单位,也就是只能分配页的整数倍的空间。已页为单位的内存确实是最利于操作系统管理的,但是当只需要小块内存区域的时候,之前的内存管理模块就无法完成了。所以在这里要完善之前的内存管理模块,使其能够支持小块内存的分配。有了底层的内存管理模块的支撑之后,malloc和free的实现就非常容易...

2018-05-19 17:33:58 322

原创 十二. 实现用户进程

TSS单核CPU想要实现多任务,唯一的方案就是多个任务共享同一个CPU,也就是让CPU在多个任务间轮转。CPU执行任务时,需要把任务运行所需要的数据加载到寄存器、栈和内存中,因为CPU只能直接处理这些数据,这是CPU在设计上就直接决定的。任务的数据和指令是CPU的处理对象,任务的执行会占用寄存器和内存。内存相对于CPU来说是低速设备,里面的数据往往被加载到高速寄存器之后被CPU处理,再将结果写到内存

2018-05-07 06:15:40 397

原创 十三. 实现系统调用

系统调用简介关于系统调用前面有过简单的介绍,这里将真正实现系统调用现代的操作系统中,用户的权限是有限的,它不能随意的访问系统中的资源。操作系统屏蔽了用户直接访问硬件的能力,这样做的原因主要是为了安全考虑。但是如果我们想控制显卡打印字符怎么呢,那就需要通过操作系统提供的接口来完成了,我们调用操作系统提供的接口,然后操作系统去操控硬件,比如说这里的显卡,打印出字符来。我们使用的c语言里面的printf函

2018-05-07 06:14:20 290

原创 十一. 线程同步

乱序输出前面完成了多线程之后,那么肯定会涉及到线程的同步问题。因为线程的执行是随机的,乱序的。虽然我们这个小kernel实现的调度器算法比较简陋,它的随机性没那么强,但是每次进行线程切换的时候,还是有可能产生问题。并且问题已经产生了。int main(void){ put_str("I am kernel\n"); init_all(); thread_start("thr

2018-05-07 06:13:28 199

原创 十. 内核线程

实现线程函数观察一下这段c语言代码void threadFunc(void *arg){ printf("thread function\n");}int main(){ printf("main function\n"); _beginthread(threadFunc, 0, NULL); return 0;}这里只是举个简单的例子,没有考虑错误处理和资源回收。在

2018-04-30 00:00:58 268

原创 八. 内存池规划

bitmap简介计算机中一些资源的数量非常庞大,比如内存容量和硬盘容量。为了使用这些资源,必须涉及到一套管理这些资源的方法,而方法中必须要构建数据结构来存储管理数据,这些数据本身也是需要占用内存的计算机中最小的单位是位,那么用一组二进制位串来管理其他单位大小的资源是很自然的,这组二进制位中的每一位与其他资源的数据单位是一一对应的关系,这实际是一种映射关系,于是这组二进制位便有了一个名字—-位图位图与

2018-04-27 19:34:15 266

原创 九. 内核的内存分配

前面已经准备好了内存池,这里就要正式实现内存的分配了。因为到目前为止,还没有用户进程,所以这里只实现内核中的动态内存分配。内存分配的过程如下: 1. 在虚拟内存池中申请n个虚拟页 2. 在物理内存池中分配物理页 3. 在页表中添加虚拟地址与物理地址的映射关系接下来就是一步步完成这三步申请虚拟页// 在虚拟内存池中申请pg_cnt个虚拟页static void *vaddr_get(enum

2018-04-27 19:33:05 383

原创 六. 函数调用约定与系统调用

函数调用约定调用约定从字面上理解,他是调用函数的一套约定。主要体现在一下三个方面 1. 参数的传递方式,参数是存放在寄存器中还是栈中 2. 参数的传递顺序,是从左到右传递还是从右到左传递 3. 是调用者保存寄存器环境还是被调用者保存在进行函数调用的时候,函数所需要传递的参数往往是不固定的。在计算机中并没有专门储存参数的硬件,因为参数的不确定性,该硬件的容量并不好确定,而且如果传递参数的过程中,

2018-04-23 15:52:14 436

原创 七. 中断

简介中断是指CPU获知了计算机中发生的某些事,CPU暂停正在执行的程序,转而去执行处理该事件的程序,当这段程序执行完了之后,CPU继续执行刚才的程序。通过中断可以极大的提高CPU的执行效率,如果没有中断,在处理器与外部设备通信时,他必须在向该设备发送指令后进入忙等待,反复轮询该设备是否就绪,这样就浪费了大量处理器的执行周期。引入中断之后,当处理器发出设备请求后就可以立即返回处理其他任务,而当设备动作

2018-04-23 15:50:53 362

原创 五. 开启分页机制

为什么有进行内存分页目前我们的小kernel还一直在分段机制下工作,因为还只有一个loader在内存中跑,所以不会出现内存不足的问题。假如说此时未开启分页功能,而物理内存空间又不足了,如下图此时进程C想要执行,但是内存空间已经不足。要么就等待进程A或者进程B执行完成,这样就有连续的内存空间了。要么就讲进程A的A3段或者进程B的B1段换到硬盘上,腾出一部分空间,同样可以容纳进程C执行等待是极其不好的用

2018-04-23 15:49:40 481

原创 四. 获取内存容量

前言在前面一篇文章中介绍了进入保护模式的方法: 1. 打开A20 2. 加载gdt 3. 将控制寄存器cr0的pe位置1 通过这三步成功的进入到保护模式下,但是在进入保护模式之前,还需要对进行内存的检测工作,启动分页机制等等,最后还要将内核加载到内存当中。这些是之前没有完成的,接下来就要完成这些进入到保护模式之前的准备工作获取物理内存大小在linux中,获取内存容量的方法有很多种,比如det

2018-04-23 15:40:13 722

原创 三. 保护模式

实模式与保护模式下的分段机制程序想要在计算机上运行,就必须将源代码编译链接成二进制的可执行文件之后才可能被操作系统加载执行。如果在加载的过程中,程序的地址都是绝对的物理地址,那么程序就必须放在一个固定的地方,那么拥有两个相同地址的程序就只能运行一个了。于是,分段机制就产生了。让CPU通过 段基址:段内偏移 来访问任意内存,这样程序就可以实现重定位。也就是说,段内偏移相对于段基址是不变的。无论段基址是

2018-04-23 15:38:54 1021

原创 二. 编写mbr,让机器启动起来

mbr简介大家都知道,在我们按下电脑电源的时候,首先启动的BIOS(基本输入输出系统),那么BIOS又是如何被启动的呢,谁来唤醒他呢,它又在何处运行呢。要了解这些的话,首先得介绍一下我们实模式的内存布局实模式的内存布局图中的内容我们现在只需要关注红色框出来的地方,可以看到BIOS的入口地址处只有16BYTE的空间,很显然,这一小块空间肯定存放的不是数据,只能是指令了,图中也写的很明显了jmp f0

2018-04-23 15:36:48 2119

原创 一. bochs环境部署

配置要求一台linux操作系统的机器即可,最好是32位的。因为我们实现的小kernel是32位的,在64的机器上进行编译和链接可能会出现某些问题。笔者这里使用的是Ubuntu16.4环境配置bochs安装与配置安装我们自制的操作系统也是运行在一个虚拟机中的,这里我们用的是bochs,bochs本身也是基于x86架构的,这也是我之前说我们的小kernel也是32位的原因 bochs下载地址 点击链接

2018-04-23 15:34:31 522

原创 从零开始,打造自己的STL(五、deque)

deque简介deque是双向开口的连续线性空间,支持内部元素的随机访问。看到这个概念,相信大家一定会想起vector,vector是单向开口的连续线性空间,内部元素也是可以随机访问的。deque的元素类似这样那么deque像比于vector的差异在哪里deque的头部插入是vector没有的,虽然从技术角度来讲,vector实现头部插入也不是很难,但是效率太低,不值得且没必要除了一些极端情况下

2018-04-23 15:29:09 256

原创 从零开始,打造自己的STL(四、list)

简述在前面我们看了vector的实现之后相信对容器有了一定的认识。容器即为存放物件之所,它代表着一块空间。想要直观的了解一个容器,那么看懂他的空间分配策略是一个非常有效的入手方式。接下来我们就来看看STL中的list又是如何实现的吧。list的结构list就是我们常说的链表,说到链表相信大家就很熟悉了。非连续空间、通过指针来连接每一个小空间、插入和删除都是O(1)操作,元素访问效率较低等等。。。

2018-04-23 15:27:49 352

原创 从零开始,打造自己的STL(三、alloc)

简述在stl中,所有的内存分配与释放都是交由allocator来实现的。在大部分情况下,我们都接触不到这里面的内容,因为它一直是隐藏在幕后悄悄的工作。 当然如果对于内存分配有特殊的要求的话,STL也提供了接口供我们使用自己的分配器 比如在vector的定义上template <typename _Tp, typename _Alloc = alloc >class vector : prote

2018-04-23 15:26:24 719

原创 从零开始,打造自己的STL(二、vector)

vector的内存布局以及操作方式与array非常的类似,都是一段连续的内存空间。两者之间唯一的差距就是空间运用的灵活性。array的空间在配置好了之后就无法更改,它所存放的数据量是固定的,一但空间不够用之后需要重新配置一块更大的空间。vector则不然,它的内存空间会随着元素的加入自动扩充新的空间供给使用,这样使用起来就不需要担心空间是否够用了。vector的内存结构vector采用了连续内存空间

2018-04-23 15:24:45 389

原创 一. 简述

简介对于每一个热爱c++的人来说,STL都是他们日常撸码、高效工作的必定会使用到的标准模板库。STL取用范型的思想,通过模板元编程,去掉了不同型别所带来的差异性,极大的提高了代码的复用性。既然STL如此强大与方便,我们当然要好好的学习它啊。仅仅停留在使用层面是是远远不够的,我们必须深入到代码内部,详细的了解它内部的工作原理。了解他不只是因为我们作为底层开发者不搞懂原理誓不罢休的精神,更是因为要更好的

2018-04-23 15:22:41 370

原创 操作系统

操作系统在操作系统没有出来之前,我们写的程序只能在一种或者一类电脑中运行.因为那个时候不同电脑之前的硬件是不一样的.1. 克服硬件的差异让我们能更好的驾驭我们的软件,我们只需要关注与操作系统的通信不用再分别对不同硬件进行处理.2. 提供统一的应用程序接口提供了一套标准化的东西, 也就是API.软件最终是通过操作硬件来达到功能的.通过操作系统提供的接口, 我们不在需要了解各种硬件参数和品牌

2017-08-07 09:35:22 397

原创 磁盘

目前硬盘的运行速度还是以MB在进行运算,它的速度远远低于CPU和内存硬盘的物理结构硬盘是以扇区的方式进行管理的. 以簇为单位进行读写 簇不是固定的大小 一般的, 1簇就是1扇区 1扇区是512字节 如果一个文件是2byte, 那么这个文件存储后是512byte 因为最小单位就是1簇 1簇不能存储2个不同的文件, 否则会导致一个文件不能正确读取.磁盘缓存磁盘缓存是为了减

2017-08-03 12:24:22 245

原创 内存

内存内存的分类ROM: 只读 RAM: 可读写内存RAM分两种: DRAM 动态RAM(Dynamic RAM) 动态随机存取存储器,需要不断的刷新,才能保存数据.而且是行列地址复用的,许多都有页模式SRAM 静态RAM(Static RAM) 静态的随机存取存储器,加电情况下,不需要刷新,数据不会丢失,而且,一般不是行列地址复用的内存中的数据断电即消内存的物理模型内存的逻辑模

2017-08-03 10:59:34 249

原创 程序与CPU

CPU程序是什么程序 = 指令 + 数据 程序: 将一些数据和指令由上而下进行排列,有某种规律的执行,这个过程叫做程序。CPU的组成寄存器: 寄存器是用来存储数据的 相当于CPU中的内存 控制器: 将内存或者寄存器的数据进行读取,写入的操作 运算器: 逻辑运算单元 时钟: 运算频率寄存器累加 ==> 做运算的标志 ==> 存储状态,进行逻辑判断程序计数 ==> 存储下一条指令地址基址 ==

2017-08-03 09:41:33 486

原创 Python--枚举类型和异常处理

枚举类型使用枚举类型可以更加直观的表示数值代表的意义>>> from enum import Enum, unique>>> @unique # 检测重复... class color(Enum):... RED = 1... GREEN = 2... BLUE = 3... >>> c = color.RED>>> print(c)color.RED

2017-07-25 14:16:16 826

原创 Python--类的高级特性

类对象的动态绑定可以绑定变量和方法 如果需要绑定的方法来调用类内部的成员,该方法的第一个参数为self 动态绑定的变量与方法只作用于该对象>>> class user_info(object):... pass... >>> def foo():... print('foo')... >>> def foo_class(self):... print(sel

2017-07-25 14:02:48 385

原创 Python类的基础使用

>>> class class_demo(object):#定义一个空类,继承自python中最大的基类object... pass... >>> c = class_demo()>>> print(type(c))<class '__main__.class_demo'>>>> c.name = 'root' #绑定变量>>> print(c.name)root>>> c

2017-07-25 12:34:15 259

原创 Python函数的高级特性

函数可以当成变量来使用>>> print<built-in function print>>>> type(print)<class 'builtin_function_or_method'>>>> print = 10>>> print10>>> type(print)<class 'int'>#也可以将一个函数赋值给变量>>> other = print>>> other(

2017-07-18 15:39:03 367

原创 Python数据结构--字典

字典由键和值组成只能用不可变的对象作为键,如字符串键必须是唯一的键值对是没有顺序的可以通过键来访问成员>>> dic = {'apple':2,'orange':1}>>> dic['apple']2字典中的方法clear()copy()fromkeys(dict)#返回与传入的dict键相同,值默认为None的字典get(key)#获取传入的键的值,如果没有该键,默认返回No

2017-07-13 16:44:15 347

原创 Python数据结构--元组

元组与列表非常类似元组内的值是不可修改的在创键只有一个元组的对象时,后面需要加一个逗号mytuple = ('1','2','3')mytuple = (1,2,3)mytuple = (1,2,3)mytuple[0] = 1#对元组内数据的修改会出错元组内部可以嵌套列表>>> mytuple = (1,2,['1','2'])>>> mytuple[2][1] = '3' #my

2017-07-13 15:20:16 208

原创 Python数据结构--list

list 和c语言中的数组比较相似可以通过下标进行访问与修改#创建一个list变量shoplist = ['apple','mango','banana']len(shoplist)#求出list中的元素个数shoplist[0]#访问第一个元素shoplist[0] = 'carrot'#修改第一个元素在list中存放的数据类型可以为一种或几种数据类型,list中也可以嵌套listm

2017-07-13 15:08:02 257

原创 Python数据类型

使用type()查看变量的类型整数Python可以处理任意大小的整数, 当然也包括负整数在程序中的标识方法和数学上的写法一摸一样在Python中, 任何一个不带小数点的数值, 我们都将之称之为整数浮点数浮点数, 也称为小数整数和浮点数在计算机内部存储方式是不同的Python中, 整数运算永远都是精确的(官方文档说的....)包括除法运算, 也是精确的而浮点数运算则可能会有四舍五入的误差

2017-07-10 13:01:11 312

c++经典面试100题

包含100道经典的c++面试题, 准备面试的同学自取.233333

2018-10-09

空空如也

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

TA关注的人

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