一. 一点说明
   一直都想写一个属于自己的操作系统,可是总是由于这样或那样的原因,一直没有集中精力去搞下来。作为一个非计算机专业的大五学生,现在忙于补修本职专业课(挂了些课)和找IT方面工作,暂时也没时间继续了。现公布一点自己些的垃圾,写得不好,请大家不要抛砖头砸我 

二.设计与实现
  硬盘多系统引导功能基本有两部分组成,包括引导启动代码安装和导启动代码. 考虑到测试的环境和处理问题的方便性, 安装程序为没有使用TASM来写。就拿从硬盘定位一个引导文件来说吧, 就得考虑该分区的文件系统类型是VFAT还是NTFS或是EXT2之类情况。由于我们的主要目的是实现多系统引导, 为了不喧宾夺主就将主要精力花在引导的设计上,至于文件系统的设计与处理,等以后有机会在于大家探讨  安装部分必须完成的任务有:保存原MBR内容,修改分区类型,恢复MBR内容,修改MBR启动代码,其他的可以安自己需要添加。
  对于多系统引导的设计与处理,考虑到代码可移植性与稳定性,没有采用默认开始执行的IP为0000:7c00,而是选择程序自己动态调整;另外为了便于测试和改进代码应该具有重定位功能,在
非引导环境下也应当能够执行(不然你没法DEBUG )


三.具体代码
  每个部分都有详细的注释,相信大家都该能够看明白.

代码:

/* MDISK.C 功能简介:
  1.)保存MBR内容
  2.)修改分区类型
  3.)删除分区
  4.)恢复MBR内容
  5.)修改MBR启动代码
*/
#include <stdio.h>
#include <conio.h>
#include <bios.h>

void main(void)
{
  FILE *fp;
  unsigned char buff[512];
  int x,y,z,ch,i,s;
  /* read MBR 
    int biosdisk(int cmd,int drive,int head,int track,int sector,int nsects,void *buffer)
  */
  /*读取MBR并检测是否改动*/
  biosdisk(2,0x80,0,0,1,1,buff);
  if(buff[3]=='H'&&buff[4]=='S'&&buff[5]=='Q')
  {
    printf("\n MBR had been modifled by HSQ ");
    printf("\n Do you want to Overlay MBR (y/n) :");
    for(ch='*';ch!='y'&&ch!='n';)ch=getchar();
    if(ch=='y')
    {
      printf("\n Enter (1-9) sector index to be read :"); /* 49-57*/
      for(x='*';x<'1'||x>'9';)x=getchar();
      biosdisk(2,0x80,0,0,x-48+10,1,buff); /* 2-10 */
      biosdisk(3,0x80,0,0,1,1,buff);
      printf("\n Overlay Complete !");
    }
  }
  else
  {  /*在处理原始MBR前,必须备份*/  
    printf("\n Save MBR to (1-9) sector index :");
    for(x='*';x<'1'||x>'9';)x=getchar();
    biosdisk(3,0x80,0,0,x-48+10,1,buff);
    printf("\n Save MBR Complete !");
  }

  /*显示操作菜单*/
  while(1)
  {
    clrscr();
    printf("\n\n Disk Partition type information :");
    for(x=0x1c2;x<=0x1f2;x+=16)printf("%02x",buff[x]);
    printf("\n\n *************** Menu Title ******************");
    printf("\n *                                           *");
    printf("\n *     1--> Change partition type            *");
    printf("\n *                                           *");
    printf("\n *     2--> Delete partition                 *");
    printf("\n *                                           *");
    printf("\n *     3--> Recover MBR                      *");
    printf("\n *                                           *");
    printf("\n *     4--> Load LDMBR File                  *");
    printf("\n *                                           *");
    printf("\n *     5--> Load BOOT File                   *");
    printf("\n *                                           *");
    printf("\n *     0--> Quit this Program                *");
    printf("\n *                                           *");
    printf("\n *  MDISK v1.23 by Huang Shiquan  2007-10-06 *");
    printf("\n *                                           *");
    printf("\n *********************************************");
    printf("\n Enter your choice :");
    for(ch='*';ch<'0'||ch>'5';)ch=getchar();
    if(ch=='0')break;
    if(ch=='1')
    {
      printf("\n Partition do you want to change (1-4) :");
      for(x='*';x<'1'||x>'4';)x=getchar();
      printf("\n Current partition type is %02x",buff[0x1c2+(x-49)*16]);
      printf("\n Enter new partition type :");
      scanf("%02x",&y);
      buff[0x1c2+(x-49)*16]=y;
      biosdisk(3,0x80,0,0,1,1,buff);
      printf("\n Change Complete !");
      getch();
    }
    if(ch=='2')
    {
      printf("\n Partition do you want to delete (1-4) :");
      for(x='*';x<'1'||x>'4';)x=getchar();
      for(x-=49,y=0;y<(3-x)*16;y++)
      {
        z=0x1be+x*16+y;
        buff[z]=buff[z+16];
      }
      for(y=0;y<16;y++)buff[0x1ee+y]=0;
      biosdisk(3,0x80,0,0,1,1,buff);
      printf("\n Delete Complete !");
      getch();
    }
    if(ch=='3')                /*调用备份扇区覆盖启动扇区*/
    {
      printf("\n Enter (1-9) sector index to read be :");
      for(x='*';x<'1'||x>'9';)x=getchar();/*HEX: 31 - DEC: 49 - ASCII: 1*/
      biosdisk(2,0x80,0,0,x-48+10,1,buff);
      biosdisk(3,0x80,0,0,1,1,buff);
      printf("\n Recover Complete !");
      getch();
    }
    if(ch=='4')                /*装载启动扇区文件*/
    {
      s=1;
      if((fp=fopen("LDMBR.COM","rb")) == NULL)
      {
        printf("\n Open file LDMBR.COM error !\n");
        break;
      }
      for(i=2;i<=10;i++)          /*执行前检查被覆盖分区是否含有MBR信息*/
      {
        biosdisk(2,0x80,0,0,i,1,buff);
        if(buff[0x1fe]==0x55&&buff[0x1ff]==0xaa)
        {
          printf("\n Warming : The [%d] sector have MBR information!",i);
            printf("\n Are you sure to continue work (y/n) :");
          for(ch='*';ch!='y'&&ch!='n';)ch=getchar();
          if(ch=='n')
          {
            s=0;break;
          }
        }
      }
      for(i=1;s==1&&i<=10;i++)        /*读入10个扇区大小的文件*/
      {
        for(x=0;x<0x200;x++)buff[x]=0;  /*初始化缓冲区*/
        fread(buff,0x200,1,fp);
        biosdisk(3,0x80,0,0,i,1,buff);
      }
      if(s==1)printf("\n Modify Complete !");
      fclose(fp);
      getch();
    }
    if(ch=='5')                /*装载启动扇区文件*/
    {
      s=1;
      if((fp=fopen("Boot.bin","rb")) == NULL)
      {
        printf("\n Open file Boot.BIN error !\n");
        break;
      }
      for(i=1;s==1&&i<=1;i++)      /*最多读入1个扇区大小的文件*/
      {
        for(x=0;x<0x200;x++)buff[x]=0;  /*初始化缓冲区*/
        fread(buff,0x200,1,fp);
        biosdisk(3,0x80,0,0,i,1,buff);
      }
      if(s==1)printf("\n Modify Boot Complete !");
      fclose(fp);
      getch();
    }
  }
  return;
}

说明: 此部分我只是具体实现了读取MBR并检测是否改动和备份,安装LDMBR和恢复MBR(功能4和5),其他的没有测试.

  • 标 题: 答复
  • 作 者:HSQ
  • 时 间:2007-12-22 16:41
  • 附 件:系统引导.rar
    详细信息:

    代码:

    ;   LDMBR.ASM 启动代码功能:
    ;  (1) 根据用户输入的分区索引号,把对应的操作系统的原MBR内容装入内存的0000:7c00处;
    ;  (2) 检测硬盘分区表变动,根据需要决定是否修改LDMBR分区信息并保存;
    ;  (3) 将控制权还给原MBR启动代码.
    ;  (4) 内含默认MBR启动代码,以便在没有可引导的MBR时使用.
    ;  (5) 支持DOS下直接远行LDMBR引导MBR.
    ;  (6) LDMBR添加代码自动定位功能,一次编译无需修改
    ;  一般情况零道零面,除BootSector(启动扇区),也就是硬盘的第一个扇区,存在重要数据
    ;  包括MBR,DPT,BRID三部分. 其余的62个扇区全部为空闲,每磁道最大扇区数为63.
    .386
    .model tiny

    code  segment byte public 'CODE' use16
      assume cs:code,ds:code
      org 100h

    start:
      call  begin
      db  'HSQ'        ;检测标志
    begin:
      cli          ;关中断
      pop  ax
      sub  ax, 3        ;ax=7C00 (DOS下不可能,需重定位)
      mov     sp, ax        ;SP=7C00
      mov  bp, ax        ;bp保存入口基址,为字符串寻址参照值
      push  cs
      push  cs
      push  cs
      pop  ds        ;DS=0 (DOS下不可能,需重定位)
      pop  ss        ;SS=0
      pop  es        ;ES=0
      sti          ;中断允许

      push  ax        ;ax为入口基址,保存作为字符串寻址参照值
      mov  bx, ax        ;bx保存,重定位标志
      add  bx, 200h
      mov  cx, 02h
      mov  ax, 020Ah      ;es=0000h    bx=7c00+200h
      mov  dx, 80h
      int  13h        ;将硬盘0道0面2扇区读入10个扇区0000:7c00处后  
             
      pop  bx        ;保存入口基址 bx
      call  ShowAuthorInformation    ;输出版权信息
          
      mov     ax, 1000h
      mov  es, ax  
      mov  di, bx  
      add  di, offset next  - 100h    ;剔除已经执行部分
      push  ax
      push  di        ;指向目的地址
      mov  si, bx        ;设置源地址 ds:si
      mov  di, bx        ;设置目的地址 es:di,di=es(保证偏移相同)
      mov     cx, offset mbr_end - 100h  ;设置 cx 为传输长度
      cld          ;设置正向传输
      rep  movsb        ;把启动代码搬到1000::offset next处
      retf          ;跳转到1000:next处
    next:      
      push  ds
      push  es        
      pop  ds        ;ds=1000h  
      pop  ax        ;es=0000h
      test  ax, ax
      je  normalboot
      xor  ax, ax        ;确保DOS下也能顺利装在原MBR到0000:7c00处
      mov  bx, 7c00h
    normalboot:
      mov  es, ax
      call  ClearScreen      ;清屏

      push  bx
      mov  bx, offset folengthtable - 100h
      add  bx, bp
      mov  di, offset fouctiontable - 100h
      add  di, bp        ;字符串寻址参照值
    showtitle:
      mov  si, [di]
      add  si, bp
      mov  cx, [bx]
      call  dbgprint      ;显示功能信息
      add  di, 2
      add  bx, 2
      cmp  word ptr [di], 0  
      jne  showtitle
      pop  bx

      mov  si, offset msg_01 - 100h
      add  si, bp        ;字符串寻址参照值
      mov  cx, msg_01_len
      call  dbgprint      ;显示输入提示信息
    read:
      xor  ah, ah
      int  16h        ;从键盘读字符
      cmp  al, '1'
      jb  read
      cmp  al, '9'
      ja  read        ;检查字符的合法性
      and  al, 0fh        ;将高四位清零
      add  al, 0ah        ;前10个扇区默认备MBR占用
      mov  cl, al        ;设置扇区号: 用户输入值  
      xor  ch, ch        ;设置磁道号: 0
    rmbr:
      mov  ax, 0201h      ;es=0000h    bx=7c00
      mov  dx, 80h
      int  13h        ;将硬盘0道0面指定扇区读入0000:7c00处
      cmp  word ptr es:[bx].1feh, 0AA55h  ;检验引导区是否合法
      je  loadDPT
      mov  si, offset msg_02 - 100h
      add  si, bp
      mov  cx, msg_02_len
      call  dbgprint      ;显示出错信息提示信息

      mov  ah, 1h
      mov  ch, 10h
      mov  cl, 0     
      int  10h        ;关闭光标
      xor  ah, ah
      int  16h        ;暂停
    reboot:
      xor  ax, ax
      mov  bx, ax
      dec  ax
      mov  es, ax        ;设置重启PC
    loadmbr:
      call  ClearScreen
      xor  ax, ax
      mov  ss, ax
      mov  sp, bx
      mov  bp, sp
      push  es
      push  bx
      retf          ;将控制权还给原MBR启动代码
    loadDPT:
      push  es        ;es=0000
      push  ds        ;ds=1000
      pop  es        ;es=1000
      pop  ds        ;ds=0000
      lea  si, [bx+1BEh]      ;bx=7c00
                ;设置源地址 ds:si=0000:7DBEh 
      lea  di, [bp+1BEh]                   ;设置目的地址 es:di=1000:7DBEh  
      mov  cx, 40h        ;10h*4
      push  si
      push  di
      repe  cmpsb        ;检测是否有必要修改分区表
      pop  di
      pop  si
      test  cx, cx
      je  same_DPT
      push  si
      mov  ax, es
      push  ds
      mov  ds, ax
      mov  si, offset msg_03 - 100h
      add  si, bp
      mov  cx, msg_03_len
      call  dbgprint      ;显示修改分区表提示信息
      pop  ds
      pop  si
    reread:
      xor  ah, ah
      int  16h        ;从键盘读字符(等待用户确认)
      cmp  al, 'n'
      je  same_DPT
      cmp  al, 'N'
      je  same_DPT
      cmp  al, 'y'
      je  upate_DPT
      cmp  al, 'Y'
      jne  reread
    upate_DPT:
      mov  cx, 40h
      rep  movsb        
      xchg  bx, bp        ;bx=7c00, bp=0100      
      mov  ax, 0301h      ;es=1000, bx=(0100)7c00
      mov  cx, 01h  
      int  13h        ;修改并保存分区信息
      xchg  bx, bp  
      jmp  reboot        ;重启兼容实际CMOS程序(在VMware中可以不重启)
      cmp  bx, bp        ;检测DOS还是启动模式
      jz      reboot
    same_DPT:
      push  ds        ;ds=0000
      pop  es        ;es=0000
      jmp  loadmbr        ;将控制权还给原MBR启动代码  
    ;未了稳定和兼容,MBR启动扇区只使用1BEH个字节,防止覆盖DPT和BRID
    currentcodelen = $ - start
    leavecodelen   = 1beh - currentcodelen    ;对齐LDMBR
      db  40h + leavecodelen dup(?),55h,0AAh
    ;*******************************以下为程序所需的数据*******************************
    yyy  equ   8                           ;上边框行值
    xxx  equ   60                          ;边框长度减二
    color  dw    5fh                         ;字符串颜色值
    gtable    dw g1-100h,g2-100h,g3-100h,g4-100h,g5-100h,g6-100h,g7-100h,g8-100h,\
                       g9-100h,0
    fouctiontable  dw fouction_00-100h,fouction_01-100h,fouction_02-100h,fouction_03-100h,\
                       fouction_04-100h,0
    folengthtable  dw fouction_01-fouction_00,fouction_02-fouction_01,fouction_03-fouction_02,\
                       fouction_04-fouction_03,msg_01-fouction_04
    chartable  dw char00a-100h,char00b-100h,char00c-100h,char01-100h,char02-100h,0
    lengthtable  dw char00b-char00a,char00c-char00b,char01-char00c,char02-char01,\
                       fouction_00-char02
    g1     db   201,xxx dup(205),187         
    g2     db   186,xxx dup(' '),186
    g3     db   186,xxx dup(' '),186
    g4     db   186,xxx dup(' '),186
    g5     db   204,xxx dup(205),185         
    g6     db   186,xxx dup(' '),186
    g7     db   199,xxx dup(196),182
    g8     db   186,xxx dup(' '),186
    g9     db   200,xxx dup(205),188         ;画边框数据
    gg     equ  $-g9                         ;边框长度
    xx     equ  (80-gg)/2                    ;让边框水平居中显示
    char00a    db  'SoftWare Version Information 1.01 Compiled By Huang Shiquan' 
    char00b    db  'Break Hard Disk Saving Card Program'                   
    char00c    db  'This program is used to break the hard disk saving card'       
    char01    db  219,219,219,178,178,177,177,176,176, ,\
            'HD Anti-Virus & Security System', ,176,176,177,177,178,178,3 dup (219)        
    char02    db  '(C)opyRight HSQ persion program company 2007.10.06' 
    fouction_00  db  'Muility Opertation System Loader V1.25',0dh,0ah,0dh,0ah
    fouction_01  db  '1.) Seclect One Opertation System For Loading',0dh,0ah
    fouction_02  db  '2.) Set A Default Opertation System For Loading',0dh,0ah
    fouction_03  db  '3.) Loading Mini DOS Opertation System By Huang Shiquan',0dh,0ah
    fouction_04  db  '4.) Remove This Muility Opertation System Loader Program',0dh,0ah
    msg_01    db  0dh,0ah,'Enter sector index (1-9) to load operation system :'
    msg_01_len = $ - msg_01
    msg_02    db  0dh,0ah,0dh,0ah,4 dup(20h),'Sorry, cant load MBR becuase its invalid.Recommend information for you:',\
            0dh,0ah,'If this problem continue, please change another sector index to try again and ',\
            0dh,0ah,'maybe solve this problem Now, Press any key to restart your PC'
    msg_02_len = $ - msg_02
    msg_03    db  0dh,0ah,0dh,0ah,4 dup(20h),'Warning, The Disk Partition Table will be replace, are you sure to do this',\
            0dh,0ah,'Sure(Y), Cancel (N) ? :'
    msg_03_len = $ - msg_03
    ;*******************************以下为应用子程序*******************************
    ClearScreen:
       pusha
             mov  ax, 0600h
             mov  bh, 7
             mov  cx, 0
             mov  dx, 184fh
             int  10h        ;清屏
       
             mov   dx, 0
             mov   ax, 2
             int   10h        ;置光标在首位
       popa
       ret
    dbgprint:
      push  ax
      push  bx
      mov  bx, 07h 
      mov  ah, 0eh
    show_continue:
      mov  al, [si]
      int  10h
      inc  si
      loop  show_continue      ;显示输入提示信息
      pop  bx
      pop  ax
      ret
    ShowAuthorInformation:
      pusha
      push  cs
      pop  es
      mov  ax, 3        ;显示版本信息
      int  10h        ;置彩色文本方式80*25*16色

      mov  ah, 1h
      mov  ch, 10h
      mov  cl, 0     
      int  10h        ;关闭光标
               
      mov  si, offset gtable -100h
      add  si, bx        ;bx为入口基址
      mov  dh, yyy        ;起始行
    show_frame:
      push  si
      mov  bp, [si]
      add  bp, bx        ;待处理串
      pop  si
      mov  dl, xx        ;起始列
      mov  cx, gg        ;串长度
      push  bx
      mov  bx, 005fh
      mov  ax, 1301h
      int  10h        ;BIOS中断调用
      pop  bx

      inc  dh
      add  si, 2
      cmp  word ptr [si], 0
      jne  show_frame      ;显示边框  

      mov  si, offset chartable -100h
      add  si, bx
      mov  di, offset lengthtable -100h
      add  di, bx
      mov  ax, 1301h      ;显示字符串,光标返回起始位
      mov  dh, yyy+1      ;起始行
    show_infromation:
      push  si
      mov  bp, [si]
      add  bp, bx        ;待处理串
      pop  si
      push  bx
      mov  cx, [di]      ;串长度
      mov  bx, 80
      sub  bx, cx
      shr  bx, 1
      mov  dl, bl        ;让字符串水平居中显示
      mov  bx, 005fh
      mov  ax, 1301h
      int  10h
      pop  bx
      cmp  dh, yyy+3
      jbe  normal_addnum
      inc  dh
    normal_addnum:
      inc  dh
      add  si, 2
      add  di, 2
      cmp  word ptr [si], 0
      jne  show_infromation    ;显示字符串
             
      xor  ah, ah
      int  16h        ;从键盘读字符

      mov  ah, 01h
      mov  ch, 0
      int  10h        ;打开光标
      popa
      ret
    mbr_end:
    code  ends
    end  start

    讨论: 当修改分区表后,在VMware中可以不重启而直接引导相应系统;可是在实际PC机上却行不通.每次当我试着跟踪,进入到到实际的OS引导代码部分一段距离时,系统就会僵死,没法继续了.不知那位知道其原由,还望赐教.

    三.效果截图和相关源码
      具体使用方法我就不说了,描述起来很麻烦的,能够看懂代码的应该就知道怎么用.我就是用这个来引导WINDOWS和LINUX以及自己的系统
    代码一帖出来,都乱了 ,我也懒得慢慢调整, 不过附件中的源码是很工整的