计数器的工作原理是这样的:它有一个输入频率,在PC上是1193180HZ.在每一个时钟周期(CLK cycle),计数器值会减1,当减到0时,就会触发一个输出.由于计数器是16位的,所以最大值是65535,因此,默认的时钟中断的发生频率就是1193180/65536约等于18.2HZ. 我们可以通过编程来控制8253.因为如果改变计数器的计数值,那么中断产生的时间间隔也就相应改变了. 比如,如果想让系统每10ms产生一次中断,也就是让输出频率为100HZ,那么需要为计数器赋值为1193180/1…
进程的切换及调度等内容是和保护模式的相关技术紧密相连的,这些代码量可能并不多,但却至关重要. 我们需要一个数据结构记录一个进程的状态,在进程要被挂起的时候,进程信息就被写入这个数据结构,等到进程重新启动的时候,这个信息重新被读出来. 在很多情况下,进程和进程调度是运行在不同的层级上的.这里本着简单的原则,我们让所有任务运行在ring1,而让进程切换运行在ring0. 诱发进程切换的原因不只一种,比较典型的情况是发生了时钟中断.但并非在每一次时钟中断时都一定会发生进程切换,不过这里为了容易理解和实…
上面的三个进程都是延迟相同的时间,让我们修改一下,尝试让它们延迟不同的时间. void TestA() { int i = 0; while (1) { disp_str("A."); milli_delay(300); } } void TestB() { int i = 0x1000; while(1){ disp_str("B."); milli_delay(900); } } void TestC() { int i = 0x2000; while(1){…
在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是应用程序和操作系统之间的桥梁. 所以,一件事情就可能是应用程序做一部分,操作系统做一部分.这样,问题就又涉及特权级变换. 很明显,这已经难不倒我们了,因为进程的切换就是不停地在重复这么一个特权级变换的过程.在那里,触发变换的是外部中断,我们把这个诱因换一下就可以了,变成"int nnn",…
我们再来添加一个任务,首先添加一个进程体: void TestC() { int i = 0x2000; while(1){ disp_str("C"); disp_int(i++); disp_str("."); delay(1); } } 然后在global.c: PUBLIC TASK task_table[NR_TASKS] = {{TestA, STACK_SIZE_TESTA, "TestA"}, {TestB, STACK_SIZE…
进程此时不仅是在运行而已,它可以随时被中断,可以在中断处理程序完成之后被恢复.进程此时已经有了两种状态:运行和睡眠.我们已经具备了处理多个进程的能力,只需要让其中一个进程处在运行态,其余进程处在睡眠态就可以了. 在main.c中进程A的代码的下面添加进程B: void TestB() { int i = 0x1000; while(1){ disp_str("B"); disp_int(i++); disp_str("."); delay(1); } } 打印的字母…
首先打开时钟中断: out_byte(INT_M_CTLMASK, 0xFE); // Master 8259, OCW1. out_byte(INT_S_CTLMASK, 0xFF); // Slave 8259, OCW1. 为了让时钟中断可以不停地发生而不是只发生一次,还需要设置EOI: hwint00: ; Interrupt routine for irq 0 (the clock). mov al, EOI ; `. reenable out INT_M_CTL, al ; / ma…
现在又出现了另外一个的问题,在中断处理过程中是否应该允许下一个中断发生? 让我们修改一下代码,以便让系统可以在时钟中断的处理过程中接受下一个时钟中断.这听起来不是个很好的主意,但是可以借此来做个试验. 首先,因为CPU在响应中断的过程中会自动关闭中断,我们需要人为地打开中断,加入sti指令:然后,为保证中断处理过程足够长,以至于在它完成之前就会有下一个中断产生,我们在中断处理例程中调用一个延迟函数.代码如下: extern delay hwint00: ; Interrupt routine f…
openresty开发系列20--lua的时间操作 在 Lua 中,函数 time.date 和 difftime 提供了所有的日期和时间功能.在 OpenResty 的世界里,不推荐使用这里的标准时间函数,因为这些函数通常会引发不止一个昂贵的系统调用,同时无法为 LuaJIT JIT 编译,对性能造成较大影响.推荐使用 ngx_lua 模块提供的带缓存的时间接口,如 ngx.today, ngx.time, ngx.utctime, ngx.localtime, ngx.now, ngx.ht…
openresty开发系列19--lua的table操作 Lua中table内部实际采用哈希表和数组分别保存键值对.普通值:下标从1开始 不推荐混合使用这两种赋值方式. local color={first="red", "blue", third="green", "yellow"} print(color["first"])                 --> output: redprint…
1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给企业带来什么,让很多人产生疑惑,那么下面就来给你解答. 我们都知道微信公众号是微信推出的一款提资讯和服务的平台应用,但却需要通过微信公众号开发技术来真正实现平台化.那么,作为想通过移动互联网来发展业务,或者需要改变目前经营状况,解决当前发展瓶颈问题的企业.商家或个体商户来说,微信公众号是一个很好的实…
org 07c00h ;伪指令,告诉编译器程序会被加载到7c00处 mov ax, cs mov ds, ax mov es, ax call DispStr ;调用显示字符串例程 jmp $ ;无限循环 DispStr: mov ax, BootMessage mov bp, ax ;ES:BP=字符串地址 mov cx, 22 ;CX=字符串长度 mov ax, 01301h ;AH=13,AL=01h mov bx, 000ch ;页号为0(BH=0)黑底红字(BL=0Ch,高亮) mov…
一个操作系统从开机到开始运行,大致经历“引导—>加载内核入内存—>跳入保护模式—>开始执行内核”这样一个过程.也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列工作,如果全都交给引导扇区来做,512字节很可能是不够用的,所以不妨把这个过程交给另外的模块来完成,我们把这个模块叫做Loader.引导扇区负责把Loader加载入内存并且把控制权交给它,其他工作放心地交给Loader来做,因为它没有512字节的限制,将会灵活得多. 为了操作方便,把软盘做成FAT12格式.这…
因为CPU只有一个,同一时刻要么是客户进程在运行,要么是操作系统在运行,如果实现进程,需要一种控制权转换机制,这种机制便是中断. 要做的工作有两项:设置8259A和建立IDT. /*======================================================================* init_8259A *======================================================================*/ PU…
实际上,我们要做的工作是根据内核的Program header table的信息进行类似下面这个C语言语句的内存复制: memcpy(p_vaddr, BaseOfLoaderPhyAddr+p_offset, p_filesz); 复制可能不止一次,如果Program header有n个,复制就进行n次. 每一个Program header都描述一个段,语句中的P_offset为段在文件中的偏移,p_filesz为段在文件中的长度,p_vaddr为段在内存中的虚拟地址. 由ld生成的可执行文件…
ELF文件的结构如下图所示: ELF文件由4部分组成,分别是ELF头(ELF header).程序头表(Program header table).节(Sections)和节头表(Section header table). 实际上,一个文件中不一定包含全部这些内容,而且它们的位置也未必如上图所示这样安排,只有ELF头的位置是固定的,其余各部分的位置.大小等信息由ELF头中的各项值来决定. ELF header的格式如下代码所示: #define EI_NIDENT 16 typedef str…
a.我们先来体验一下在Linux下用汇编编程的感觉,见代码 [section .data] ; 数据在此 strHello db "Hello, world!", 0Ah STRLEN equ $ - strHello [section .text] ; 代码在此 global _start ; 我们必须导出 _start 这个入口,以便让链接器识别 _start: mov edx, STRLEN mov ecx, strHello mov ebx, 1 mov eax, 4 ; sy…
一直以来,我们把所有的段描述符都放在GDT中,而不管它属于内核还是用户程序,为了有效地在任务之间实施隔离,处理器建议每个任务都应当具有自己的描述符表,称为局部描述符表LDT,并且把专属于自己的那些段放到LDT中. 和GDT一样,LDT也是用来存放描述符的.不同之处在于,LDT只属于某个任务.或者说,每个任务都有自己的LDT,每个任务私有的段,都应当在LDT中进行描述.另外,LDT的第1个描述符,也就是0号槽位,也是有效的.可以使用的. [SECTION .gdt] ; GDT ; 段基址, 段界…
于是我换了一个思路来理解这个typedef 我们首先看常规的变量定义: int INT//定义了一个名为INT的int型变量. char *c//定义了一个名为c的char型指针变量 void(*Fun)(void);//定义了一个名为Fun的,返回值为void,无参数的函数指针 加上typedef以后,就可以理解为,原来的变量名变成了自己本身对应的类型名 如INT就代表了int类型 c就变成了char* Fun就代表了“返回值为void,无参数的函数指针”型 理解typedef的关键就是,别把…
8259A虽然已经设置完成,但是我们还没有真正开始使用它呢. 所有的中断都会触发一个函数spurious_irq(),这个函数的定义如下: PUBLIC void spurious_irq(int irq) { disp_str("spurious_irq: "); disp_int(irq); disp_str("\n"); } spurious_irq()其实什么也不做,仅仅是把IRQ号打印出来而已. 其实现在已经可以make并运行了,但是不会有什么效果,因为我…
先来看一个简单的Makefile,我们把它放在目录/boot下,可以用来编译boot.bin和loader.bin. # Makefile for boot # Programs, flags, etc. ASM = nasm ASMFLAGS = -I include/ # This Program TARGET = boot.bin loader.bin # All Phony Targets .PHONY : everything clean all # Default starting…
现在把esp.GDT等内容放进内核中,我们现在可以用C语言了,只要能用C,我们就避免用汇编. 下面看切换堆栈和GDT的关键代码: ; 导入函数 extern cstart ; 导入全局变量 extern gdt_ptr [SECTION .bss] StackSpace resb 2 * 1024 StackTop: ; 栈顶 ; 把 esp 从 LOADER 挪到 KERNEL mov esp, StackTop ; 堆栈在 bss 段中 sgdt [gdt_ptr] ; cstart() 中…
现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了. 首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段.一个0~4GB的可读写段和一个指向显存开始地址的段: ; GDT ; 段基址 段界限, 属性 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_CR|DA_32|DA_LIMIT_4K ;0-4G LABEL_DESC_FLAT_RW: D…
Loader要做两项工作,我们先来做第一项,把内核加载到内存: 1.加载内核到内存. 2.跳入保护模式. 首先编译无内核时: nasm boot.asm -o boot.bin nasm loader.asm -o loader.bin dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc sudo mount -o loop a.img /mnt/hgfs/ sudo cp loader.bin /mnt/hgfs/ -v sudo umoun…
返回<8天掌握EF的Code First开发>总目录 本篇目录 管理数据库创建 管理数据库连接 管理数据库初始化 填充种子数据 LINQ to Entities详解 什么是LINQ to Entities 使用LINQ to Entities操作实体 LINQ操作 懒加载和预加载 插入数据 更新数据 删除数据 本章小结 自我测试 本篇的源码下载:点击下载 先附上codeplex上EF的源码:entityframework.codeplex.com,此外,本人的实验环境是VS 2013 Upda…
本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 管理数据库创建 管理数据库连接 管理数据库初始化 填充种子数据 LINQ to Entities详解 什么是LINQ to Entities 使用LINQ to Entities操作实体 LINQ操作 懒加载和预加载 插入数据 更新数据 删除数据 本章小结 本人的实验环境是VS 2013 Update 5,windows 10,MSSQL Server 2008. 上一篇<Code First开发系列之领域建…
原文:[Xamarin开发 Android 系列 13] 应用打包部署 开始倒叙咯................ 先更新大宝部署吧,这个章节比较的Easy,童鞋们不用费脑筋.点解?从界面上填写几个参数,其他都是傻瓜式的[下一步],童鞋们是否喜欢.卤煮 反正很是受用. 我们开发好的程序,需要打包成 .apk,成为安卓的安装包.然后就可以通过下载的形式安装到 用户终端手机/平板/TV/Watch....... 发布程序 主要的还是将应用发布到 谷歌的官方商店 Google Play..再然后就是其…
原文:循序渐进学.Net Core Web Api开发系列[13]:中间件(Middleware) 系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如何使用中间件(Middleware). 二.初步演练 先写几个中间件 public class DemoAMiddleware { private readonly RequestDelegate _…
本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 创建控制台项目 根据.Net中的类来创建数据库 简单的CRUD操作 数据库模式更改介绍 本章小结 本人的实验环境是VS 2012,windows 7,MSSQL Server 2008 R2. 创建控制台项目 1. 新建控制台应用项目 2. 通过NuGet安装Entity Framework 6 根据.Net中的类来创建数据库 上面的步骤之后,我们就可以开始写代码了.在写代码之前,你要始终记得,每个类就是相应…
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如何使用中间件(Middleware). 二.初步演练 先写几个中间件 public class DemoAMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public Dem…