GRUB0.93 源码阅读分析(分析asm.S、commen.c)---(3)

asm.S是stage2的重要组成部分,它的作用主要是调用commen.c的c函数,而该函数会利用asm.S提供的函数进行各种引导前设置,将multiboot相关的各种内容准备好。-------------------------------------------------

I. asm.S

-------------------------------------------------

 #ifdef STAGE1_5
# define ABS(x) ((x) - EXT_C(main) + 0x2200)
#else
# define ABS(x) ((x) - EXT_C(main) + 0x8200)

#endif
//pgnotes: 注意这里的EXT_C宏在调用c函数的时候,可以自动将函数名前面加上"_",视

//#ifdef HAVE_ASM_USCORE而定(FIXME)

 

 ADDR32 movl %ebp, EXT_C(install_second_sector)

//pgnotes: ADDR32/DATA32编译器用的,因为前面有.code16实模式的说明

 

ENTRY(real_to_prot)
 .code16
 cli

 /* load the GDT register */
 DATA32 ADDR32 lgdt gdtdesc

 /* turn on protected mode */
 movl %cr0, %eax
 orl $CR0_PE_ON, %eax
 movl %eax, %cr0   //pgnotes: 参考ia,置1个bit即可进入保护模式

 /* jump to relocation, flush prefetch queue, and reload %cs */
 DATA32 ljmp $PROT_MODE_CSEG, $protcseg  //pgnotes:将cs赋值为8000段

 /*
  *  The ".code32" directive only works in GAS, the GNU assembler!
  *  This gets out of "16-bit" mode.
  */
 .code32

protcseg:
 /* reload other segment registers */
 movw $PROT_MODE_DSEG, %ax  //pgnotes: 0x10, 选择子,对应于gdt中5个描述符的第3个,装载了选择子,就有了BASE和
LIMIT/ATTR
 movw %ax, %ds
 movw %ax, %es
 movw %ax, %fs
 movw %ax, %gs
 movw %ax, %ss

 /* put the return address in a known safe location */
 movl (%esp), %eax    //pgnotes: call 指令将地址压入了堆栈
 movl %eax, STACKOFF    //pgnotes: 将返回地址放入0x2000-0x10这个地址内

 /* get protected mode stack */
 movl protstack, %eax    //pgnotes: 这个地址现在不明白...
 movl %eax, %esp
 movl %eax, %ebp

 /* get return address onto the right stack */
 movl STACKOFF, %eax
 movl %eax, (%esp)    //pgnotes:将返回地址放入保护模式下的新堆栈

 /* zero %eax */
 xorl %eax, %eax

 /* return on the old (or initialized) stack! */
 ret         //pgnotes:设置完保护模式后返回call之后的语句

 

 /* clean out the bss */   //pgnotes:bss段,存储全局变量和静态变量,使用前要清零的。

 /* set %edi to the bss starting address */
#if defined(HAVE_USCORE_USCORE_BSS_START_SYMBOL)
 movl $__bss_start, %edi
#elif defined(HAVE_USCORE_EDATA_SYMBOL)
 movl $_edata, %edi
#elif defined(HAVE_EDATA_SYMBOL)
 movl $edata, %edi
#endif

 /* set %ecx to the bss end */
#if defined(HAVE_END_SYMBOL)
 movl $end, %ecx
#elif defined(HAVE_USCORE_END_SYMBOL)
 movl $_end, %ecx
#endif

 /* compute the bss length */
 subl %edi, %ecx    //pgnotes:bss段长度计算,起始、结束地址具体被哪个变量赋值的,望指教(FIXME)
 
 /* zero %al */
 xorb %al, %al

 /* set the direction */
 cld
 
 /* clean out */
 rep
 stosb       //pgnotes:循环将es:edi赋值为0, ecx计数
 
 /*
  *  Call the start of main body of C code, which does some
  *  of it's own initialization before transferring to "cmain".
  */
 call EXT_C(init_bios_info)    //pgnotes:跳转到commen.c中的c函数执行

 


-------------------------------------------------

II. commen.c部分代码分析

-------------------------------------------------

//pgnotes: init_bios_info (void)首先调用get_memsize ();

/* memory probe routines */
int
get_memsize (int type)
{
  if (! type)
    return CONVENTIONAL_MEMSIZE >> 10; //pgnotes: 640*1024byte>>10= 640k, 按照multiboot协议,需要以k为单位
  else
    return EXTENDED_MEMSIZE >> 10;  //pgnotes: 3*1024*1024byte>>10 = 3072k
}


  gateA20 (1);       //pgnotes: 允许访问1M以上内存,而不会回转

 

 

      cont = get_mmap_entry ((void *) addr, cont);  //pgnotes: 通过do.while逐步将预先定义好的内存map填到addr地址处

 

下面我们看看get_mmap_entry ():

int
get_mmap_entry (struct mmar_desc *desc, int cont)
{
  /* Record the memory map statically.  */
  static struct mmar_desc desc_table[] =
  {
    /* The conventional memory.  */
    {
      MMAR_DESC_LENGTH,        //pgnotes: 20,每个struct24字节,所以每次需要加20+4,来逐步定位结构数组的下一个
元素。
      0,
      CONVENTIONAL_MEMSIZE,      
      MMAR_DESC_TYPE_AVAILABLE      //pgnotes: 0~640k, 是OS可用内存
    },
    /* BIOS RAM and ROM (such as video memory).  */
    {
      MMAR_DESC_LENGTH,
      CONVENTIONAL_MEMSIZE,
      0x100000 - CONVENTIONAL_MEMSIZE,    //pgnotes: 640k~1M的内存是BIOS使用的比如VGA ROM、shadow memory
      MMAR_DESC_TYPE_RESERVED      //pgnotes: reserved类型,OS不可用
    },
    /* The extended memory.  */
    {
      MMAR_DESC_LENGTH,
      0x100000,
      EXTENDED_MEMSIZE,        //pgnotes: 1M~ 1M+ 3M也是OS可用
      MMAR_DESC_TYPE_AVAILABLE
    }
  };
 
  int num = sizeof (desc_table) / sizeof (*desc_table); //pgnotes: num等于3

  if (cont < 0 || cont >= num)
    {
      /* Should not happen.  */
      desc->desc_len = 0;
    }
  else
    {
      /* Copy the entry.  */
      *desc = desc_table[cont++];

      /* If the next entry exists, return the index.  */
      if (cont < num)
 return cont;
    }
 
  return 0;
}


      /*
       *  This is to get the lower memory, and upper memory (up to the
       *  first memory hole), into the "mbi.mem_{lower,upper}"
       *  elements.  This is for OS's that don't care about the memory
       *  map, but might care about total RAM available.
       */  //pgnotes: 有的OS不关心mmap...(懒啊),所以我们计算好可用的内存大小,分别到下面两个变量里
      mbi.mem_lower = mmap_avail_at (0) >> 10;   //pgnotes: 调用后mbi.mem_lower= 640, 单位k
      mbi.mem_upper = mmap_avail_at (0x100000) >> 10; pgnotes: 调用后mbi.mem_lower= 3072, 单位k.

 

      /* Find the maximum available address. Ignore any memory holes.  */
      for (max_addr = 0, addr = mbi.mmap_addr;
    addr < mbi.mmap_addr + mbi.mmap_length;
    addr += *((unsigned long *) addr) + 4)
 {
   struct AddrRangeDesc *desc = (struct AddrRangeDesc *) addr;
  
   if (desc->Type == MB_ARD_MEMORY && desc->Length > 0
       && desc->BaseAddr + desc->Length > max_addr)
     max_addr = desc->BaseAddr + desc->Length;  //pgnotes:for完了,就把1M+3M这个地址放到了max_addr
 }


下面这段程序将addr指向的地址放入drive相关的数据结构,并且保存该地址到mbi.drives_addr.

  mbi.drives_length = 0;
  mbi.drives_addr = addr;

  /* For now, GRUB doesn't probe floppies, since it is trivial to map
     floppy drives to BIOS drives.  */
  for (drive = 0x80; drive < 0x88; drive++)
    {
      struct geometry geom;
      struct drive_info *info = (struct drive_info *) addr;
      unsigned short *port;
     
      /* Get the geometry. This ensures that the drive is present.  */
      if (get_diskinfo (drive, &geom))   //pgnotes: 该函数将struct geometry赋值
 break;
     
      /* Clean out the I/O map.  */
      grub_memset ((char *) io_map, 0,
     IO_MAP_SIZE * sizeof (unsigned short));

      /* Disable to probe I/O ports temporarily, because this doesn't
  work with some BIOSes (maybe they are too buggy).  */
#if 0
      /* Track the int13 handler.  */
      track_int13 (drive);
#endif

      /* Set the information.  */
      info->drive_number = drive;
      info->drive_mode = ((geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
     ? MB_DI_LBA_MODE : MB_DI_CHS_MODE);
      info->drive_cylinders = geom.cylinders;
      info->drive_heads = geom.heads;
      info->drive_sectors = geom.sectors;

      addr += sizeof (struct drive_info);
      for (port = io_map; *port; port++, addr += sizeof (unsigned short))
 *((unsigned short *) addr) = *port;

      info->size = addr - (unsigned long) info;
      mbi.drives_length += info->size;
    }

 

上面的程序中get_diskinfo (drive, &geom)   值得看看,但也就这一行比较有用:

      version = check_int13_extensions (drive);  //pgnotes:这个汇编函数有protect-->real-->protect,原因是需要用实模式下的中断,保护模式下还没有设置中断向量寄存器。类似的其他的中断处理,也都是在asm.S中这样处理的。

commen.c中的下面的部分就不细说了,最后会通过调用cmain()到stage2.c中继续执行。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值