国产又色又爽又黄刺激在线观看还铭刻刚刚的超纲图吧
发布日期:2022-09-23 05:03    点击次数:104
久久不见久久见海南话国产又色又爽又黄刺激在线观看

书接上回,上回书我们说到,time_init 要领通过与 CMOS 端口进行读写交互,获取到了年月日时候秒等数据,并通过这些狡计出了开机时代 startup_time 变量,是从 1970 年 1 月 1 日 0 时起到开机那时经过的秒数。

我们不绝往下看,大名鼎鼎的程度调遣运涟漪,shed_init。

void main(void) {     ...     mem_init(main_memory_start,memory_end);     trap_init();     blk_dev_init();     chr_dev_init();     tty_init();     time_init();     sched_init();     buffer_init(buffer_memory_end);     hd_init();     floppy_init();          sti();     move_to_user_mode();     if (!fork()) {init();}     for(;;) pause(); } 

这要领可了不得,因为它等于多程度的基石!

终于来到了兴隆的时刻,是不是很清翠?不外先别清翠,这里仅仅程度调遣的运涟漪,也等于为程度调遣所需要用到的数据结构做个准备,果然的程度调遣还需要调遣算法、时钟中断等机制的合营。

天然,关于归拢操作系统,经由和数据结构最为紧迫了,而这一段当作通盘这个词经由的开赴点,以及建设数据结构的地点,就显得格外紧迫了。

我们参加这个要领,小数点往后看。

void sched_init(void) {     set_tss_desc(gdt+4, &(init_task.task.tss));     set_ldt_desc(gdt+5, &(init_task.task.ldt));     ... } 

两行代码运涟漪了下 TSS 和 LDT。

先别急问这俩结构是啥。还铭刻之前讲的全局描绘符表 gdt 么?它在内存的这个位置,何况被树立成了这个神色。

忘了的看一下等八回 | 烦死了又要再行树立一遍 idt 和 gdt,这就诠释之前看似没用的细节有多紧迫了,全球一定要有耐烦。

说回这两行代码,其实等于往后又加了两项,别离是 TSS 和 LDT。

好,那再说说这俩结构是干嘛的,不外本篇先肤浅归拢,背面会详备讲到。

TSS 叫任务情状段,等于保存和复原程度的陡立文的,所谓陡立文,其实等于各个寄存器的信息资料,这么程度切换的时候,智力做到保存和复原陡立文,不绝本质。

由它的数据结构你应该不错看出点道理。

struct tss_struct{     long back_link;     long esp0;     long ss0;     long esp1;     long ss1;     long esp2;     long ss2;     long cr3;     long eip;     long eflags;     long eax, ecx, edx, ebx;     long esp;     long ebp;     long esi;     long edi;     long es;     long cs;     long ss;     long ds;     long fs;     long gs;     long ldt;     long trace_bitmap;     struct i387_struct i387; }; 

而 LDT 叫局部描绘符表,是与 GDT 全局描绘符表相对应的,内核态的代码用 GDT 里的数据段和代码段,而用户程度的代码用每个用户程度我方的 LDT 里得数据段和代码段。

先不论它,我这里放一张超纲的图,你先找找嗅觉。

我们接着往下看。

struct desc_struct {     unsigned long a,b; }  struct task_struct * task[64] = {&(init_task.task), };  void sched_init(void) {     ...     int i;     struct desc_struct * p;         p = gdt+6;     for(i=1;i<64;i++) {         task[i] = NULL;         p->a=p->b=0;         p++;         p->a=p->b=0;         p++;     }     ... } 

这段代码有个轮回,干了两件事。

一个是给一个长度为 64,结构为 task_struct 的数组 task 附上运转值。

这个 task_struct 结构等于代表每一个程度的信息,这然而个卓著卓著紧迫的结构了,把它放在心里。

struct task_struct { /* these are hardcoded - don't touch */     long state; /* -1 unrunnable, 0 runnable, >0 stopped */     long counter;     long priority;     long signal;     struct sigaction sigaction[32];     long blocked; /* bitmap of masked signals */   /* various fields */     int exit_code;     unsigned long start_code,end_code,end_data,brk,start_stack;     long pid,father,pgrp,session,
背景图片leader;     unsigned short uid,euid,suid;     unsigned short gid,egid,sgid;     long alarm;     long utime,stime,cutime,cstime,start_time;     unsigned short used_math;   /* file system info */     int tty;  /* -1 if no tty, so it must be signed */     unsigned short umask;     struct m_inode * pwd;     struct m_inode * root;     struct m_inode * executable;     unsigned long close_on_exec;     struct file * filp[NR_OPEN];   /* ldt for this task 0 - zero 1 - cs 2 - ds&ss */     struct desc_struct ldt[3];   /* tss for this task */     struct tss_struct tss; }; 

这个轮回做的另一件事,是给 gdt 剩下的位置填充上 0,也等于把剩下留给 TSS 和 LDT 的描绘符都先附上空值。

往后瞻望一下的话,等于以后每创建一个新程度,就会在背面添加一组 TSS 和 LDT 默示这个程度的任务情状段以及局部描绘符表信息。

还铭刻刚刚的超纲图吧,将来通盘这个词内存的议论等于这么的,不外你先无谓归拢得很细。

那为什么一最先就先有了一组 TSS 和 LDT 呢?目下也没创建程度呀。错了,目下天然我们还莫得建设动身度调遣的机制,但我们正在运行的代码等于会当作将来的一个程度的辅导流。

也等于当将来程度调遣机制一建设起来,正在本质的代码就会化身成为程度 0 的代码。是以我们需要提前把这些将来会当作程度 0 的信息写好。

要是你以为很狐疑,别急,等背面通盘这个词程度调遣机制建设起来,何况让你亲眼看到程度 0 以及程度 1 的创建,以及它们背面因为程度调遣机制而切换,你就明显这一切的真谛了。

好,收总结,运涟漪了一组 TSS 和 LDT 后,再往下看两行。

#define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))) #define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n)))  void sched_init(void) {     ...     ltr(0);     lldt(0);     ... } 

这又触及到之前的常识咯。

还铭刻 lidt 和 lgdt 辅导么?一个是给 idtr 寄存器赋值,以告诉 CPU 中断描绘符表 idt 在内存的位置;一个是给 gdtr 寄存器赋值,以告诉 CPU 全局描绘符表 gdt 在内存的位置。

那这两行和刚刚的通常,av好的关键词国产ltr 是给 tr 寄存器赋值,以告诉 CPU 任务情状段 TSS 在内存的位置;lldt 一个是给 ldt 寄存器赋值,以告诉 CPU 局部描绘符 LDT 在内存的位置。

这么,CPU 之后就能通过 tr 寄存器找到当远景度的任务情状段信息,也等于陡立文信息,以及通过 ldt 寄存器找到当远景度在用的局部描绘符表信息。

我们不绝看。

void sched_init(void) {     ...     outb_p(0x36,0x43);      /* binary, mode 3, LSB/MSB, ch 0 */     outb_p(LATCH & 0xff , 0x40);    /* LSB */     outb(LATCH >> 8 , 0x40);    /* MSB */     set_intr_gate(0x20,&timer_interrupt);     outb(inb_p(0x21)&~0x01,0x21);     set_system_gate(0x80,&system_call);     ... } 

四行端口读写代码,两行树立中断代码。

端口读写我们也曾很熟习了,等于 CPU 与外设交互的一种花式,之前讲硬盘读写以及 CMOS 读写时,也曾构兵过了。

而此次交互的外设是一个可编程定时器的芯片,这四行代码就开启了这个定时器,之后这个定时器变会持续的、以一定频率的向 CPU 发出中断信号。

而这段代码中树立的两个中断,第一个等于时钟中断,中断号为 0x20,中断处理才略为 timer_interrupt。那么每次定时器向 CPU 发出中断后,便会本质这个函数。

这个定时器的触发,以实时钟中断函数的树立,是操作系统主导程度调遣的一个要津!莫得他们这么的外部信号不竭触发中断,操作系统就莫得目的当作程度解决的主人,通过强制的手艺收回程度的 CPU 本质权限。

第二个树立的中断叫系统调用 system_call,中断号是 0x80,这个中断又是个相等相等相等相等相等相等相等紧迫的中断,通盘效户态才略想要调用内核提供的要领,都需要基于这个系统调用来进行。

比如 Java 才略员写一个 read,底层会本质汇编辅导 int 0x80,这就会触发系统调用这个中断,最终调用到 Linux 里的 sys_read 要领。

这个过程之后会重心报告,目下只需要澄莹,在这个地点,暗暗把这个极为紧迫的中断,树立好了。

是以你看这一章的内容,暗暗树立了影响程度和影响用户才略调用系统要领的两个分量级中断处理函数,不肤浅呀~

到目下为止,中断也曾树立了不少了,我们目下望望所树立好的中断有哪些。

中断号 中断处理函数 0 ~ 0x10 trap_init 里树立的一堆 0x20 timer_interrupt 0x21 keyboard_interrupt 0x80 system_call

其中 0-0x10 这 17 个中断是 trap_init 里运涟漪树立的,是一些基本的中断,比如除零极端等。这个在 第14回 中断运涟漪 trap_init 有讲到。

之后,在国法台运涟漪 con_init 里,我们又树立了 0x21 键盘中断,这么按下键盘就有反映了。这个在 第16回 国法台运涟漪 tty_init 有讲到。

目下,我们又树立了 0x20 时钟中断,何况开启定时器。终末又暗暗树立了一个极为紧迫的 0x80 系统调用中断。

找到些嗅觉没,有莫得越来越发现,操作系统有点靠中断驱动的道理,各个模块不竭运涟漪各式中断处理函数,何况开启指定的外设开关,让操作系统我方冉冉“活”了起来,缓缓通过中断贫困于各式事情中,无法自拔。

恭喜你,我们也曾缓缓在接近操作系统的实质了。

追念一下我们今天干了什么,就三件事。

第一,我们往全局描绘符表写了两个结构,TSS 和 LDT,当作将来程度 0 的任务情状段和局部描绘符表信息。

第二,我们运涟漪了一个结构为 task_struct 的数组,将来这里会存放通盘程度的信息,何况我们给数组的第一个位置附上了 init_task.init 这个具体值,亦然当作将来程度 0 的信息。

第三,树立了时钟中断 0x20 和系统调用 0x80,一个当作程度调遣的开赴点,一个当作用户才略调用操作系统功能的桥梁,相等之紧迫。

背面,我们将会缓缓看到,这些紧迫的事情,是若何邃密且精妙地结伙在一道,证实特等妙的作用。

欲知后事若何,且听下回判辨。

本文转载自微信公众号「低并发编程」,不错通过以下二维码善良。转载本文请关系低并发编程公众号。本网站已取得低并发编程的授权