xv6的main.c

 

 

//Bootloader

//

//Part of the boot sector ,along with  bootasm.s which calls bootmain()

//bootasm.S has put the processor into  processor into protected 32-bit mode

//bootmain() loads an ELF kernel image from the disk  starting at

//sector 1 and then jumps to the kernel entry routine

#include "type.h"

#include"elf.h"

#include"x86.h"

#define SECTSIZE  512

void readseg(uint ,uint ,uint);

void bootmain(void)

{

 

             struct  elfhdr *elf;

             struct  proghdr*ph,*eph;

             void (*entry)(void);

             elf=(struct elfhdr *)0x10000;

             readseg ((uint)elf,8*sectsize,0);

            if (elf->magic!=ELF_MAGIC)

             goto bad;

            // Load each program segment (ignores ph flags).
 // ph代表ELF段表首地址
  ph = (struct proghdr*)((uchar*)elf + elf->phoff);
 //eph代表ELF段表末地址
  eph = ph + elf->phnum;

//循环读取每段

 for(;ph<eph;ph++)

readseg(ph->va&0xFFFFFF,ph->memsz,ph->offset);

//call the entry point  from the elf header

//Does not return!

entry =(void(*)(void))(elf->entry&0xFFFFFF)

entry();

//错误处理

bad:

crt[pos++] = ('E'&0xff) | 0x0700;  // black on white
  outw(0x8A00, 0x8A00);
  outw(0x8A00, 0x8E00);
  for(;;)

  ;

}

void
readsect(void *dst, uint offset)
{
  // Issue command.
  waitdisk();
  outb(0x1F2, 1);   // count = 1
  outb(0x1F3, offset);
  outb(0x1F4, offset >> 8);
  outb(0x1F5, offset >> 16);
  outb(0x1F6, (offset >> 24) | 0xE0);
  outb(0x1F7, 0x20);  // cmd 0x20 - read sectors

  // Read data.
  waitdisk();
  insl(0x1F0, dst, SECTSIZE/4);
}

// Read 'count' bytes at 'offset' from kernel into virtual address 'va'.
// Might copy more than asked.
void
readseg(uint va, uint count, uint offset)
{
  uint eva;

  eva = va + count;

  // Round down to sector boundary.
  va &= ~(SECTSIZE - 1);

  // Translate from bytes to sectors; kernel starts at sector 1.
  offset = (offset / SECTSIZE) + 1;

  // If this is too slow, we could read lots of sectors at a time.
  // We'd write more to memory than asked, but it doesn't matter --
  // we load in increasing order.
  for(; va < eva; va += SECTSIZE, offset++)
    readsect((uchar*)va, offset);
}

 

注释:1:Bootloader 需要将磁盘上的内核映像加载在内存中,内存映像是elf 格式文件

类似于“字典“,由头部(header)和许多节区组成;

elf 文件结构:

 

2:#define SECTSIZE 512 //一个扇区的大小

#define ELFHDR   ((struct Elf*)0x10000)

定义ELF文件头的位置,在内存的0x10000处

void readsect(void*,uint32_t);//读取磁盘上的一个扇区,扇区的偏移为参数

void readseg(uint32_t,uint32_t,uint32_t);

读取ELF文件中的一个段,第一参数表示链接地址,转换后为加载地址,第二参数表示段的字节数,第三参数为该段相对于文件头的偏移;

3:elfhdr.h的数据结构:

struct elf

{

uint  magic; //

uchar elf[12];

ushort type;

ushort machine;

uint version;

uint entry;//ELF程序的入口虚拟地址

uint phoff;//程序头表的相对于文件头的偏移地址

uint shoff;//section headertable在文件中的偏移量

uint flags;

ushort ehsize;//ELF header的大小

ushort phentsize;//程序头表中的每个条目的大小

ushort phnum;//程序头表中的条目数

ushort shentsize;//

ushort shnum;

ushort  shstrndx;

};

4:proghdr.h

struct proghdr

{

uint type;//段类型

uint offset;//段相对于文件头的偏移

uint va;//段的第一个字节将被放到内存虚拟地址

uint pa;

uint filesz;//段在文件中的大小

uint memsz;段在内存映射中所占的字节数

uint flags;

uint align;

};

5:void readseg(uint va,uint count,uint offset)//函数readseg调用readsect函数以扇区为单位

{

    uint eva;

    eva=va+count;

    va&=~(SECTSIZE-1);

    offset=(offset/SECTSIZE)+1;//以扇区为单位

    for(;va<eva;va+=SECTSIZE,offset++)

     readsect((uchar*)va,offset);

}

 

readsect(void *dst,uint offset)

{//使用LBA模式对磁盘进行读操作

 

    waitdisk();

    outb(0x1F2,1);//每次读写前都要设置读写扇区的数量,最小读写数量是1,

    outb(0x1F3,offset);//如是LBA模式表示LBA参数0~7

    outb(0x1F4,offset>>8);//如是LBA模式表示LBA参数8~15

    outb(0x1F5,offset>>16);//如是LBA模式表示LBA参数16~23

    outb(0x1F6,(offset>>24)|0xE0);//0~3位,如是LBA模式就是24~27 ,第4位:0代表主盘 ,1代表从盘 第6位:1=LBA模式,0=chs模式 ;第5位和第7位必为1;

    outb(0x1F0,0x20); //读数据,当0x1f7不为忙状态时,可以读!

    waitdisk();

    insl(0x1F0,dst,SECTSIZE/4);//读磁盘上数据到内存中;这里的命令是内嵌汇编指令的宏定义在x86.h中:static  inline void insl(int port,void *addr,int cnt)

{

   asm volatile ("cld/n/trepne/n/tinsl":"=D"(addr),"=c"(cnt):"d"(port),"0"(addr),"1"(cnt):"memory","cc");

  }

  其中"=D"表示输出寄存器EDI(变址寄存器之一)的缩写,可以当指针使用;

   “=c"代表ecx;"0"代表输入寄存器EDI,“1”代表输入寄存器ecx;"="表示输出操作数(目标操作数)是只写的!

   “memory”表示modify部分;表示操作完成后内存中的内容已经改变

 

 

 

 

 

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值