Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1163915
  • 博文数量: 53
  • 博客积分: 1165
  • 博客等级: 下士
  • 技术积分: 1811
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-19 14:56
个人简介

专注于操作系统内核的实现

文章分类
文章存档

2015年(2)

2014年(16)

2013年(18)

2012年(17)

分类: LINUX

2012-10-10 09:16:32

      很多朋友要求我将LMOS开源,这个问题我还没想好,不过我可以将一些框架
性的东西公开,这些代码是用于描述框架的。大家可以看看吧。
      中断处理框架:
      这里我很想骂人了,因为现在大多数理论性的操作系统教程,一开始就讲进
程以及进程相关的算法进而什么互斥啊、同步啊、死锁啊,等等一大堆。我承认
操作系统中进程是很重要,但不是最重要的。也许读者看了半天,终于明白进程
是啥玩意儿了,可是终究不能明白在操作系统内部是如何组织若干进程让CPU去
执行它们又是如何从它们手中夺回CPU,又分给其它进程的。有些教程还在开始
简要的提及了中断,但是并没说为什么要中断,以及中断了该做些啥。以至于读
者还是会感觉是一知半解,当然对付考试还是可以的,呵呵。在我看来一本脱离
了具体硬件平台的操作系统教程,那就是空中楼阁,终究不能让读者彻头彻尾的
了解操作系统的。
      我可以告诉大家操作系统中执行最频繁的代码就是中断处理代码,而不是其
它别的。我很难想像一硬件平台不提供中断那会是什么样子。
      好了大家看代码吧,我在次申明这些代码只是描述性的,只是和LMOS中大
相近庭,还请大家不要把这些十分糟糕的代码到处复制-粘贴。
     中断处理代码:
   
;************************************************************
;*  底层核心文件Kernel.asm                                    *
;*                                 彭东  @ 2011.12.01.10.00 *
;************************************************************
.....
ALIGN 16
GxH_hxi_hwint: //这个标号的地址,会被内核的初始化程序写
                             //入处理器的中断描述表中。
         pushad        //这是将x86cpu的8个通用寄存器压入当前线程
                             //(我的系统内核中基本的执行单元是线程,
                             //也有进程不过它只是描述一个线程的“执行
                             //所需资源”的“容器”一个进程内可包含多
                             //个线程)的内核态堆栈    。
         push    ds
         push    es
         push    fs
         push    gs
                            //把这4个数据段寄存器也压入堆栈,一句话
                            //上面这些汇编指令就是为了保存机器状态
                            //以便下次能重新启动
 
         mov     di, ss 
         mov     ds, di
         mov     es, di
         mov     gs, di
                           //把段寄存器设成0号特权级的段的索引,你
                           //用用户级特权,去访问内核级特权级数据
                           //或者代码就处理器电路就产生通常是14号
                           //保护异常。
 
         push    %1 
                           //压入当前中断号,为调用GxH_intpt_allocator
                           //准备参数,C语言调用协议都是
                           //调用者准备参数和清理堆栈。
         call    GxH_intpt_allocator
                           //调用中断总分发器,进入它后就会调用相
                           //应的中断服务程序了。
         add     esp,4  
                           //清理堆栈。
         pop gs        
         pop fs
         pop es
         pop ds
         popad       //这堆代码, 恢复线程的机器状态。
         iretd          //中断返回。
............

/**********************************************************
  中断总分配器源文件intallocator.c
***********************************************************
                            彭东 @ 2011.12.21.10.20
**********************************************************/
PUBLIC  void GxH_intpt_allocator(u32_t intnumb)
{
        u32_t svflags,intflags;
       
        GxH_save_interrupt(&intflags);
                          //保存当前中断控制器的状态
        
        GxH_irq_mask((u8_t)intnumb);
                          //关掉当前中断号的中断信号
                          //线,以免发生中断重入。
 
        GxH_save_flags_sti(&svflags); 
                          //开启处理器的中断,以便可
                          //以响应其它中断,处理器在
                          //响应中断时会自动关掉中断.
        GxH_do_irq_up_thread(intnumb);
                          //唤醒(通常情况会执行)当
                          //前中断服线程这种设计很前
                          //卫,不管是windows还是linux 
                          //它们中断服务程序都是以函
                          //数(也就是代码段)的形式
                          //存在的,也就是说一旦产生
                          //中断那么中断服务程序必须
                          //被执行,它们永远占据着系
                          //统中最高优先权,可能对其
                          //它线程造成很大的延迟,然
                          //而这对系统的响应实时性应
                          //用,是极其不利的,比如说
                          //核电站的温度监控线程,和
                          //火箭发动机的控制线程,经
                          //不起丝毫的等待,不是吗,
                          //在说了我的内核讲究世法平
                          //等,没有谁能有特权,每个
                          //线程调度的优先权,都是动
                          //态的,被调度的次数越多,
                          //优先权就会越低,没有谁会
                          //“撑爆”也没有谁会“饿死”
 
           if(sched_read_sdneedsched()==MD_SD_NEEDSCHED||
           sched_read_preempt()==MD_SD_PREEMPT)
           {        
                          //这里会检查内核的调度和抢
                          //占标志,只要有一个其中一
                          //个条件满足,就会激发调度
                          //机制从而选取更值得执行的
                          //线程运行,我的内核是可抢
                          //占的,只有拥有自旋锁和信
                          //号量的代码段是不被抢占的
                          //其它都行。
                          schedul();
           }
           GxH_restore_flags_cli(&svflags);
                          //关掉处理器中断,因为内核
                          //代码控制路经到这里,说明
                          //内核的任务已经做完了,准
                          //备恢复线程(可能是另一个
                          //线程)的机器状态了,把处
                          //理器控制权还给用户的应用
                          //软件比如QQ,KUGOU,哈哈 
         GxH_restore_interrupt(&intflags);
                          //打开当前中断号的中断信号线。
         return;
}


   下面看看LMOS中的进程是如何组织的:

/**********************************************************
初始化进程调度器头文件init_sched_t.h
***********************************************************
彭东 @ 2012.04.01.16.30
**********************************************************/
#ifndef _INIT_SCHED_T_H
#define _INIT_SCHED_T_H



#define MD_SD_SMCHEAD_NR (CPU_MAX_NRS+1)
#define MD_SD_NOTCPUSIDLE (CPU_MAX_NRS+2)

typedef struct s_PER_CPUSCHED
{
spinlock_t pscd_lock;
u32_t pscd_cpuphyid;
u32_t pscd_cpuid;
u32_t pscd_iscpu_idle;
u32_t pscd_abrunflags;
u32_t pscd_td_nr;
u32_t pscd_ps_nr;
atomic_t pscd_needsched;
atomic_t pscd_preempt_idx;
struct s_THREAD* pscd_td_current;  
struct s_PROC* pscd_ps_current;
struct s_THREAD* pscd_td_cpuidle;
struct s_PROC* pscd_ps_cpuidle;
list_h_t pscd_a_b_run_hl;
list_h_t pscd_b_a_run_hl;
list_h_t pscd_new_hl;
list_h_t pscd_run_hl;
list_h_t pscd_sleep_hl;//各种状态的进程队列头
list_h_t pscd_block_hl;
list_h_t pscd_wait_hl;
list_h_t pscd_dead_hl;
list_h_t pscd_cach_hl;
//略......
}per_cpusched_data_t;

typedef struct s_SCHED_MCHEAD
{
spinlock_t sd_lock;
list_h_t sd_list;
atomic_t sd_needsched;
atomic_t sd_preempt_idx;
atomic_t sd_allisnidle;//用于判断哪个CPU负载最低
u32_t sd_td_nr;
u32_t sd_ps_nr;
per_cpusched_data_t sd_cpuscheddata[MD_SD_SMCHEAD_NR];
//有多少
        //CPU就有多少个;
atomic_t sd_ps_idcount;
atomic_t sd_td_idcount;
//略......
}sched_mchead_t;

      //略......
#endif

   由于LMOS是支持多CPU的内核,那么就需要对各种全局数据结构进行保护。
   下面看看LMOS自旋锁的实现:
/**********************************************************
自旋锁头文件spinlock.h
***********************************************************
彭东 @ 2012.01.15.16.00
**********************************************************/
#ifndef _SPINLOCK_H
#define _SPINLOCK_H



KLINE void x86_spin_lock_init(spinlock_t * lock)
{
lock->lock = 0;

}

KLINE void x86_spin_lock(spinlock_t * lock)
{
    __asm__ __volatile__ (
"1: \n\t"
"lock; xchg  %0, %1 \n\t"
"cmpl $0, %0 \n\t"
"jnz 2f \n\t"
".section .spinlock.text,""\"ax\"""\n\t"// 重新定义一个代码段
//所以jnz 2f下面并不是
"2: \n\t" //cmpl $0,%1 事实上
//下面的代码不会常常执行,
"cmpl $0, %1 \n\t" //这是为了不在cpu指令
//高速缓存中填充无用代码
"jne 2b \n\t" //要知道那可是用晶体管
//做的双极性静态
"jmp 1b \n\t" //储存器,比内存条快得多。
".previous \n\t"
:
: "r"(1), "m"(*lock));
}

KLINE void x86_spin_unlock(spinlock_t * lock)
{
    __asm__ __volatile__(
"movl $0, %0\n\t"
:
: "m"(*lock));
}

KLINE void x86_spin_lock_cli(spinlock_t * lock,u32_t* flags)
{

__asm__ __volatile__(
        "pushfl                 \n\t"
        "cli                    \n\t"
"popl %0                \n\t"
"1: \n\t"
"lock; xchg  %1, %2 \n\t"
"cmpl $0,%1 \n\t"
"jnz 2f \n\t"
".section .spinlock.text,""\"ax\"""\n\t"// 重新定义一个代码段
//所以jnz 2f下面并不是
"2: \n\t" //cmpl $0,%1 事实上下
//面的代码不会常常执行,
"cmpl $0,%2 \n\t" //这是为了不在cpu指令
//高速缓存中填充无用代码
"jne 2b \n\t" //要知道那可是用晶体管
//做的双极性静态
"jmp 1b \n\t" //储存器,比内存条快得多
".previous \n\t"
:"=m"(*flags)
: "r"(1), "m"(*lock));

}

KLINE void x86_spin_unlock_sti(spinlock_t* lock,u32_t* flags)
{

__asm__ __volatile__(
"movl $0, %0\n\t"
"pushl %1 \n\t"
        "popfl \n\t"
:
: "m"(*lock), "m"(*flags));

}

#endif

       暂不提供更多的信息。不好意思了。大家见谅。
       这么丑陋的代码,公开实在是惭愧死我了。还请大家看看吧。喷青就不
要看了,哈哈,另外还请大家不要拿着我的代码,到处乱说话,谢谢。
阅读(7292) | 评论(12) | 转发(0) |
给主人留下些什么吧!~~

lmnos2014-11-13 09:43:56

yzl0208994:对于做嵌入式的,你说的这种问题还是比较入门的。所以如果要搞这种与硬件相关的底层,还是可以先学习一下嵌入式软件的知识。

搞清楚这是x86上的 ,关于嵌入式,请看我最新的文章

回复 | 举报

yzl02089942014-11-13 09:12:53

对于做嵌入式的,你说的这种问题还是比较入门的。所以如果要搞这种与硬件相关的底层,还是可以先学习一下嵌入式软件的知识。

最大行业软件2012-10-22 15:32:08

lmnos: 谢谢 我的OS是全32位的,不支持16位的程序 任务切换并没有用i386硬件提供的机制,那个机制烦索又慢,还要为每个线程建个TSS,但IA64架构的不在提供任务切换的硬.....
PTC Pro/E WildFire+Pro/Mechancia 3.0 M080 for Linux-ISO 1DVD

PTC.Pro.Engineer.Wildfire.Graphics.Library.v3.0-ISO 1CD
#########################################
联系电话 Phone: 139  782  44459
QQ:5269150    QQ:5269150    QQ:5269150
希望我们诚信的服务为您带来效益
Email: fffsoft@t

lmnos2012-10-14 21:16:07

fanhed: 开发自己的工具链就没必要了吧?可以用gnu的,不爽gpl那也可以选择llvm的。.....
关键是这些工具链的接口都是某一特定系统的,不能在LMOS上运行,如果要运行在LMOS上,需要大量的移植工作

lmnos2012-10-14 21:12:56

fanhed: hi,我最近也在研究操作系统底层的东西,有些东西想请教一下。不知有没有其他联系方式?gtalk之类?.....
我没有gtalk