xv6的main.c

原创 2011年01月11日 16:29:00

 

 

//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部分;表示操作完成后内存中的内容已经改变

 

 

 

 

 

 


 

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

在linux debian系统上写个hello world版的bootloader

根据http://viralpatel.net/taj/tutorial/hello_world_bootloader.php这篇文章来做的。 准备: nasm qemu 安装nasm和qem...

xv6的bootloader之一bootasm.s

bootasm.S是bootloader(bootasm.S和bootmain.c)其中之一:start:.code16set  PRO    0x001set  PRO    0x002set  c...

xv6引导及初始化详解

了解xv6的引导及初始化部分格外重要,因为它奠定了整个xv6操作系统的基础和框架。 按照执行的顺序,整个引导及初始化的基本流程如下: bootasm.S     处于实模式,设置并加载gdt、使能A2...

xv6的lab1中的proj1的bootmain.c

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

xv6的bootloader之bootmain.c

xv6 系统中的bootloader 程序的组成之一是bootmain.c部分的功能:加载硬盘的kernel部分到内存中;#include"type.h"#incude"xv6.h"#include"...

ucos在s3c2410上运行过程整体剖析(6)-从main函数到UCOS初始化完毕 .

http://blog.csdn.net/zhanglianpin 下面要讲解的内容基本上都是c语言编写的了,还有一部分代码是用汇编写的。以下我就以这个系统移植的实验源码为例做详细讲解。讲解的方式是...

XV6操作系统的安装与使用

1.1  XV6操作系统的安装与使用     麻省理工大学的网站上 http://pdos.csail.mit.edu/6.828/2011/xv6.html,已经对XV6的来龙去脉及如何下载做了较详...
  • SheIsC
  • SheIsC
  • 2015-06-27 22:07
  • 2056

xv6源码分析(三):锁

锁 xv6支持多核心CPU,计算机上有多个同时运行代码的CPU,但是所有CPU共享同一个地址空间,为了保护数据结构的一致性,xv6需要某一种机制来防止它们互相干扰。其实即使在单处理器的抢占内核中,也...

xv6之添加alarm CPU中断检测

第三次修改了。再次记录下。 作业要求: In-class: xv6 CPU alarm We encourage you to collaborate with others on these...

xv6 一个简单的,类unix适于教学的操作系统

Contents 0  操作系统接口 1 第一个进程 2 页表 3 陷阱(traps), 中断,以及驱动 4 锁 5 调试 (scheduling) 6 文件系统 A PC 硬件 B boot loa...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)