操作系统与网络实现 之十七

来源:互联网 发布:ubuntu交叉编译环境 编辑:程序博客网 时间:2024/05/22 08:13

设备枚举

linux中设备枚举是个很复杂的过程,设备登记,建立链表,等等等等......,我们这里大大简化了,因为我们知道bochs虚拟机pci总线,有网卡,这些是已知的,那么“检测有什么设备”这个步骤就可以省略,只要直接找到它就行了,这样简单了很多。

实际上大家电脑配置都不一样,但是用bochs虚拟机与大家的电脑实际配置是没有关系的,bochs虚拟出来的设备都是一样的,比如bochs2.6.8,它的网卡就是Ne2000兼容网卡。

首先要修改配置文件bochsrc.bxrc,才能检测到想要的这些虚拟设备。

###############################################################

# bochsrc file for flopy image.

 

# how much memory the emulated machine will have

megs: 32

# filename of ROM images

romimage: file=../BIOS-bochs-latest

vgaromimage: file=../VGABIOS-lgpl-latest

# what disk images will be used

floppya: 1_44=a.img, status=inserted

# choose the boot disk.

boot: a

# where do we send log messages?

log: bochsout.txt

# the mouse

mouse: enabled=0

# 增加这两项

ne2k: irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=\Device\NPF_GenericDialupAdapter

pci: enabled=1, chipset=i440fx, slot1=ne2k

###############################################################

 

随着计算机的发展,出现了即插即用功能,过去一台计算机可能只有少数几个设备I/O端口的分配是由人手工进行的,

但是现在一台计算机可能有越来越多的设备,那么在使用前必须保证它们不相互冲突,即插即用的意思,就是不再人手指定端口地址,而是由系统分配

bochs也随着计算机技术的发展而发生变化。

bochs2.6里对网卡是这样设置:

ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0

但是在bochs2.6.8不再对网卡指定I/O端口地址,模拟的是即插即用功能bochs2.6.8里对网卡是这样设置:

ne2k: irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=\Device\NPF_GenericDialupAdapter

 

我们将在bochs2.6使用dlxlinux进行网络实验,在对网络传输有了一个感性认识后,回到bochs2.6.8,编写我们自己的网络代码。

 

调试小方法及运行结果:

有时候我们想知道程序运行是否正常,数据是否和我们想要的一样,那么我们利用bochs调试模式里查看数据功能,插入下面的代码,就可以看到运行结果了:

unsignedint*ID =(void*)0x400000;//数据存于此,bochsdbg中用x/50 0x400000查看

*( ID )= regVal;//存入regVal

ID +=1;//地址指针指向下一个双字

 

 

 

wps238.tmp

 

红线标出来的数值,0x80001000是下一段程序要用到的数值,

其中0x802910ec8029表示ne2000兼容网卡rtl802910ec 表示设备厂商为 Realtek

80861237      Intel Corporation   440FX - 82441FX PMC [Natoma]  

8086 7000   82371SB PIIX3 ISA [Natoma/Triton II]  PIIX3 PCI-to-ISA Bridge (Triton II)

8086 7010   storage ide 82371SB PIIX3 IDE [Natoma/Triton II]  PIIX3 IDE Interface (Triton II)

8086 1237   440FX - 82441FX PMC [Natoma]   PCI & Memory

8086 7020   82371SB PIIX3 USB [Natoma/Triton II]  PIIX3 USB Host Controller (Triton II)

8086 7113   82371AB/EB/MB PIIX4 ACPI   PIIX4/4E/4M Power Management Controller

 

 

 

wps239.tmp

 

看红线标出的数值:

0xc041最后1位等于1,表示这个基地址属于I/O空间,最后两位清零,就是网卡的IO空间基址

 

对端口地址=网卡的IO空间基址+0x10 反复读,就可以得到网卡的mac地址。

网卡的mac地址为了兼容,每个字节要保存两次,顺序颠倒过来,所以读出来的结果是这样的:

c4c4 b0b0  00002020 01010000  最后5757是结束标志,因为顺序是颠倒的,它表达的数据就是b0 c4 20 00 00 01

上面数值与bochsrc.bxrc中设定的网卡端口地址是一致的:

mac=b0:c4:20:00:00:01

 

 

 

代码:

 

boot.asm

[BITS 16]                                                   ;编译成16位的指令

[ORG 0x7C00]

jmp                 main

 

read_kernelloader:                                         ;读入 kernelloader 程序

  push              es

 

  .rkl:

  mov               ax , 0x1000                            ;kernelloader.bin 所在的段基址           

  mov               es , ax

  mov               bx , 0                                  ;写入到内存0x1000:0000

  mov               ah , 2

  mov               dl , 0                                  ;驱动器号

  mov               ch , 0                                  ;磁道

  mov               cl , 2                                  ; 2个扇区开始

  mov               al , 2                                  ;读入扇区数,每个扇区为 512B

  int               0x13 

  jc                .rkl

 

  pop               es

  ret

 

main:                                                        ;主程序         

  mov               ax , 0x0                                ;boot.asm 程序的段基址

  mov               ds , ax

 

  call              read_kernelloader                      ;读入 kernelloader 程序 

 

  jmp dword         0x1000:0                                ;跳转到 kernelloader 处执行

times 510-($-$$) db 0

db 0x55

db 0xAA

 

 

 

kernelloader.asm

[BITS 16]  

jmp                 main

 

gdt_entries    equ    3         ;共有三个段描述符:null,os code32,os data32

 

pe              equ    1         ;bit PE in CR0

null            equ    0h

os_code32_sel equ    8h        ;1,gdt,rpl=00

os_data32_sel equ    10h    ;2,gdt,rpl=00

VESA:       times 256 db 0      ;分配一块区域存放 vesa 返回的信息,大小256,我们只需要其中的一个32位值

pdescr      times 6 db 0

gdt_table    times (gdt_entries*8) db 0

 

set_video_mode:                              ;设置显卡模式

  push              es

 

  ;设置显卡模式

  mov               ax , 0x4f02

  mov               bx , 0x4114             ;800X600 ( 5:6:5 ) 16位色

  int               0x10

  ;取得该模式下显存线性地址

  mov               bx , 0x1000

  mov               es , bx

  mov               di , VESA  ;es:di指向256空间,int 10h将在此填写数据

  mov               ax , 0x4f01

  mov               cx , 0x114

  int               0x10

  ;40个字节开始存有显存地址0xe0000000,将此地址再存入指定的地址0x10050

  mov               eax , [ es:VESA + 40 ]

  ;将此地址再存入指定的地址0x10050,因为实际运行中,在0x10040-0x10120都没有填入数据,都是可以利用的

  mov               [ es:0x50 ] , eax            ;es:bx 0x1000:0050=0x10050 内容为 0xe0000000

   

  pop               es

  ret

read_charpic:                          ;读入字库及图片

  push              es

  mov               ah , 2              ;磁盘读

  mov               dl , 0              ;驱动器号

  .rc1:

  mov               bx , 0x1000         ;asc16 所在的段基址           

  mov               es , bx

  mov               bx , 0x0400         ;写入到内存0x1000:0400 物理地址=0x10400

  mov               dh , 0               ;磁头

  mov               ch , 0               ;磁道

  mov               cl , 4               ;开始扇区

  mov               al , 15              ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc1

 

  add               bx , 15*512          ;读入地址增加

  mov               di , 6                ;读入磁道数

  mov               dh , 1                ;磁头

  mov               ch , 0                ;磁道 

  call              readtrack

 

  .rc2:

  mov               ah , 2               ;磁盘读 

  mov               dh , 1               ;磁头

  mov               ch , 3               ;磁道

  mov               cl , 1               ;开始扇区

  mov               al , 3               ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc2

;开始0x20000 

  mov               ah , 2               ;磁盘读

  mov               dl , 0               ;驱动器号

  .rc3:

  mov               bx , 0x2000          ;所在的段基址           

  mov               es , bx

  mov               bx , 0x0000          ;写入到内存物理地址0x20000

  mov               dh , 1               ;磁头

  mov               ch , 3               ;磁道

  mov               cl , 4               ;开始扇区

  mov               al , 15              ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc3

 

  add               bx , 15*512          ;读入地址增加

 

  mov               di , 6                ;读入磁道数

  mov               dh , 0               ;磁头

  mov               ch , 4               ;磁道

  call              readtrack

 

  .rc4:

  mov               ah , 2               ;磁盘读

  mov               dh , 0               ;磁头

  mov               ch , 7               ;磁道

  mov               cl , 1               ;开始扇区

  mov               al , 5               ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc4

 

;开始0x30000 

  mov               ah , 2               ;磁盘读

  mov               dl , 0               ;驱动器号

  .rc5:

  mov               bx , 0x3000          ;所在的段基址           

  mov               es , bx

  mov               bx , 0x0000          ;写入到内存物理地址0x30000

  mov               dh , 0               ;磁头

  mov               ch , 7               ;磁道

  mov               cl , 6               ;开始扇区

  mov               al , 13              ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc5

 

  add               bx , 13*512           ;读入地址增加

 

  mov               di , 6               ;读入磁道数

  mov               dh , 1               ;磁头

  mov               ch , 7               ;磁道

  call              readtrack

 

  .rc6:

  mov               ah , 2               ;磁盘读

  mov               dh , 1               ;磁头

  mov               ch , 10               ;磁道

  mov               cl , 1               ;开始扇区

  mov               al , 7               ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc6 

 

;开始0x40000 

  mov               ah , 2               ;磁盘读

  mov               dl , 0               ;驱动器号

  .rc7:

  mov               bx , 0x4000          ;所在的段基址           

  mov               es , bx

  mov               bx , 0x0000          ;写入到内存物理地址0x40000

  mov               dh , 1               ;磁头

  mov               ch , 10              ;磁道

  mov               cl , 8               ;开始扇区

  mov               al , 11              ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc7

 

  add               bx , 11*512          ;读入地址增加

 

  mov               di , 6               ;读入磁道数

  mov               dh , 0               ;磁头

  mov               ch , 11              ;磁道

  call              readtrack

 

  .rc8:

  mov               ah , 2               ;磁盘读

  mov               dh , 0               ;磁头

  mov               ch , 14              ;磁道

  mov               cl , 1               ;开始扇区

  mov               al , 9               ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc8

 

;开始0x50000 

  mov               ah , 2               ;磁盘读

  mov               dl , 0               ;驱动器号

  .rc9:

  mov               bx , 0x5000          ;所在的段基址           

  mov               es , bx

  mov               bx , 0x0000          ;写入到内存物理地址0x50000

  mov               dh , 0               ;磁头

  mov               ch , 14              ;磁道

  mov               cl , 10              ;开始扇区

  mov               al , 9               ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc9

 

  add               bx , 9*512            ;读入地址增加

 

  mov               di , 6               ;读入磁道数

  mov               dh , 1               ;磁头

  mov               ch , 14              ;磁道

  call              readtrack

 

  .rc10:

  mov               ah , 2               ;磁盘读

  mov               dh , 1               ;磁头

  mov               ch , 17              ;磁道

  mov               cl , 1               ;开始扇区

  mov               al , 11              ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc10

 

;开始0x60000 

  mov               ah , 2               ;磁盘读

  mov               dl , 0               ;驱动器号

  .rc11:

  mov               bx , 0x6000          ;所在的段基址           

  mov               es , bx

  mov               bx , 0x0000          ;写入到内存物理地址0x60000

  mov               dh , 1               ;磁头

  mov               ch , 17              ;磁道

  mov               cl , 12               ;开始扇区

  mov               al , 7                ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc11

 

  add               bx , 7*512            ;读入地址增加

 

  mov               di , 6               ;读入磁道数

  mov               dh , 0               ;磁头

  mov               ch , 18              ;磁道

  call              readtrack

 

  .rc12:

  mov               ah , 2               ;磁盘读

  mov               dh , 0               ;磁头

  mov               ch , 21              ;磁道

  mov               cl , 1               ;开始扇区

  mov               al , 13              ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc               .rc12

 

;开始0x70000 

  mov               ah , 2               ;磁盘读

  mov               dl , 0               ;驱动器号

  .rc13:

  mov               bx , 0x7000          ;所在的段基址           

  mov               es , bx

  mov               bx , 0x0000           ;写入到内存物理地址0x70000

  mov               dh , 0                ;磁头

  mov               ch , 21               ;磁道

  mov               cl , 14               ;开始扇区

  mov               al , 1                ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rc13

 

  pop es

  ret 

 

;读入几个磁道子程序

;;di  读入的磁道总数

;;dh  磁头

;;ch  开始磁道

readtrack:

  .r_1:

  mov               ah , 2                                  ;;功能号 2 表示读磁盘扇区

  mov               cl , 1                                  ;;启始扇区1扇区

  mov               al , 18                                 ;;读入扇区数

  int               0x13

  jc                .r_1

  add               bx , 18 * 512      ;读入地址增加

  dec               di

  cmp               di , 0

  je                .r_2

 

  xor               dh , 1           ;反转磁头

;这里与磁盘读写独特的规律有关,0.0 1.0 0.1 1.1 0.2 1.2 ......如果反转值为0,磁道数要加1

 

  cmp               dh , 0         

  jne               .r_1

  inc               ch

  jmp               .r_1

 

  .r_2:

  ret

 

read_kernel:                               ;读入 kernel 程序

  push              es

 

  .rk:

  mov               ax , 0x8000         ;kernel.bin 所在的段基址           

  mov               es , ax

  mov               bx , 0               ;写入到内存0x8000:0000 物理地址=0x80000

  mov               ah , 2

  mov               dl , 0               ;驱动器号

  mov               dh , 0               ;磁头0

  mov               ch , 26              ;磁道

  mov               cl , 1               ;1个扇区开始

  mov               al , 18              ;读入扇区数,每个扇区为 512B

  int               0x13   

  jc                .rk

 

  pop               es

  ret

 

main:

mov ax,1000h

mov ds,ax

;设置显卡模式

call              set_video_mode

;读入 kernel

call              read_kernel

;读入字库及图片

call read_charpic

;打开 A 20 地址线

mov               ax , 0x2401

int               0x15 

;[1]built up GDT table

cli

mov  eax,gdt_table

;item 0:null descriptor,

mov  dword[eax],0

mov  dword[eax+4],0

add  eax,8

;item 1,OS code32 descriptor,

;Base=00000000h,limit=0ffh,G=1,D=1,type=a,dpl=0

mov  word[eax],0ffh

mov  word[eax+2],0

mov  byte[eax+4],00h

mov  byte[eax+5],09ah

mov  byte[eax+6],0c0h

mov  byte[eax+7],00h

add  eax,8

;item 2,OS data32 descriptor

;Base=00000000h,Limit=0fffffh,G=1,D=1,Type=2,DPL=0

mov  word[eax],0ffffh

mov  word[eax+2],0000h

mov  byte[eax+4],00h

mov  byte[eax+5],092h

mov  byte[eax+6],0cfh    ;高四位是G D 0 AVL,此处为1100 = c ,低四位是limit bit 16-19 此处为f

mov  byte[eax+7],00h

add  eax,8

;[2]built false GDT descriptor

mov  word[pdescr+0],(gdt_entries*8)

mov  dword[pdescr+2],gdt_table+00010000h

lgdt [pdescr]

;[3]enter into protected mode

;刷新CR0

mov eax,cr0

or  eax,pe

mov cr0,eax

jmp flush

flush:

mov ax,os_data32_sel

mov ds,ax

mov es,ax

mov ss,ax

mov fs,ax

mov gs,ax

jmp dword os_code32_sel:0x80000  ;跳转到0x8000:0000保护模式  物理地址0x80000

 

 

kernel.asm

[BITS 32]

[GLOBAL start]      ;我们必须导出start这个入口,以便让链接器识别 ,

[EXTERN _ya_main]   ;用到本文件外定义的函数 在kernel.c

jmp                 start

start:

call _ya_main        ;调用C

jmp $

 

 

kernel.c

#include "..\include\graph.h"

#include "..\include\pciprobe.h"

 

unsignedshort color ;

void ya_main()

{

//写字的颜色

color = rgb_mix(0,255,255);

unsignedint x =250;

unsignedint y =50;

if(PciBusProbe()){

ya_draw_chars(250,50,"北桥存在", color);

}

PciProbe();

netcardprobe();

}

 

 

graph.c

#include "..\include\graph.h"

unsigned int * addr = (int *)0x10050 ;

 

 

// 颜色合成函数

unsigned short rgb_mix( unsigned char r , unsigned char g , unsigned char b )

{

  union{

    unsigned int color ;

    struct{

      unsigned char b : 5 ;

      unsigned char g : 6 ;

      unsigned char r : 5 ;

    }sa;

  }ua;

  ua.sa.r = r >> 3 ;

  ua.sa.g = g >> 2 ;

  ua.sa.b = b >> 3 ;

  return ua.color ;

}

 

// 画点函数

void draw_dot( unsigned int x , unsigned int y , unsigned short color )

{

  // 取得显卡地址

  //unsigned short *video_addr ;

  unsigned int mid = *addr ;

  unsigned short * video_addr = (unsigned int *)mid ;

 

  // 计算点的偏移量

  unsigned int offset = y * 800 + x ; 

//  *( video + offset ) = color ;

*( video_addr + offset ) = color ;

}

 

 

 

// 显示英文

void ya_draw_english( unsigned int x , unsigned int y , unsigned int addr_in_font , unsigned short color )

{

unsigned char *english_font = ( unsigned char * )(0x10400 + addr_in_font * 16) ;

int ta = y ;

int tb = x ;

unsigned char font_char ;

for (int tc = 0; tc < 16; tc++) { // 一个英文 16

        for (int td = 7; td >= 0; td--) { // 一行一个字节 八位

            tb++ ;

            if ((font_char = english_font[ tc ] & (1 << td))) {

                draw_dot(tb, ta, color);

}

        }

        ta++; // 显示下一行

        tb = x;

    }

}

 

// 显示汉字

void ya_draw_chinese( unsigned int x , unsigned int y , unsigned int addr_in_font , unsigned short color )

{

unsigned char *chinese_font = ( unsigned char * )(0x11400 + addr_in_font * 32) ;

int ta = y ;

int tb = x ;

unsigned char font_char ;

for (int tc = 0; tc < 16; tc++) { // 一个汉字16

    for (int te =0 ; te < 2; te++){  // 一行两个字节 十六位

for (int td = 7; td >= 0; td--) {

tb++ ;

if ((font_char = chinese_font[ tc*2 + te ] & (1 << td))) {

                draw_dot(tb, ta, color);

}

            }

    }

        ta++; // 显示下一行

        tb = x;

    }

}

 

// 显示字符串

void ya_draw_chars( int x, int y, char *chars , unsigned short color)

{

while (*chars){

char ch = *chars++ ;

if (ch & 0x80){ //是中文

char cl = *chars++ ;

cl -= 0xa1;

ch -= 0xa1;

int addr = 94*ch + cl ; 

ya_draw_chinese( x , y , addr , color);

x += 16 ;

}

else{ //是英文

int addr = ch ; 

ya_draw_english(x , y , addr , color);

x += 8 ;

}

}

}

 

 

 

void ya_draw_4bit_bmp(unsigned int x ,unsigned int y ,unsigned int addr)

{

int color [16] = {0x0,0x8000,0x400,0x8400,0x10,0x8010,0x410,0x8410,0xc618,0xf800,0x7e0,0xffe0,0x1f,0xf81f,0x7ff,0xffff} ;//调色板值

int lx = x ;                          //每行要从这里开始,保留这个值

int * ta = (int *)(addr+0xa) ;        //位图数据开始偏移量 在第0xa字节共四字节

int * tb = (int *)(addr+0x22) ;       //位图数据长 在第0x22字节共四字节

int * width = (int *)(addr+0x12) ;    //位图宽  在第0x12字节共四字节

int * height = (int *)(addr+0x16) ;   //位图高 在第0x16字节共四字节

int td ;  //一行要读的字节数

int te ;  //补几个字节

int tf ;  //图宽

tf =  * width ;

switch(tf%8){   //计算一行要读的字节数td  要补的字节数te

case 0:

td = tf/2  ; 

te = 0 ;

break ;

case 1:

td = (tf+1)/2  ; 

te = 3 ;

break ;

case 2:

td = tf/2  ; 

te = 3 ;

break ;

case 3:

td = (tf+1)/2  ; 

te = 2 ;

break ;

case 4:

td = tf/2  ; 

te = 2 ;

break ;

case 5:

td = (tf+1)/2  ; 

te = 1 ;

break ;

case 6:

td = tf/2  ; 

te = 1 ;

break ;

case 7:

td = (tf+1)/2  ; 

te = 0 ;

break ;

}

int tc = td + te ;

char * string = (char *)(addr+*ta+*tb-tc) ;  //数据从最末端-32字节处开始

for(int i=0 ; i< *height ;i++){

for(int j=0 ; j<td ;j++){

unsigned char ch = *string ;    //一个字符有八位,要分别取得其高四位和低四位

            unsigned char c1 = ch>>4;       //取得高四位

unsigned int pa = color[c1] ;   //取得调色板的对应颜色值

if(pa!=0xffff){                 //如果是白色,跳过不显示

draw_dot(x , y , pa ) ;

}

        unsigned char c2 = ch & 0xf;    //取得低四位

pa = color[c2] ;                //取得调色板的对应颜色值

if(pa!=0xffff){

draw_dot(x , y , pa ) ;

}

string++ ;

x++ ;

}

string = string + te -tc*2;   //必须是四个字节宽,X个字节,然后后退XX字节

x = lx ;

y++;

}

}

 

 

port.c

unsigned char readb( unsigned short P )         //读字节8

{

  unsigned char result ;

  __asm__( "in %%dx , %%al" : "=a"( result ) : "d"( P ) ) ;

  return result ;

}

 

unsigned short readw( unsigned short P )         //读字16

{

  unsigned short result ;

  __asm__( "in %%dx , %%ax" : "=a"( result ) : "d"( P ) ) ;

  return result ;

}

 

unsigned int readl( unsigned short P )         //读双字32

{

  unsigned int result ;

  __asm__( "in %%dx , %%eax" : "=a"( result ) : "d"( P ) ) ;

  return result ;

}

 

 

 

void writeb( unsigned short P , unsigned char val )   //写字节8

{

  __asm__( "out %%al , %%dx" : : "a"( val ) , "d"( P ) ) ;

}

 

void writew( unsigned short P , unsigned short val )   //写字16

{

  __asm__( "out %%ax , %%dx" : : "a"( val ) , "d"( P ) ) ;

}

 

void writel( unsigned short P , unsigned int val )   //写双字32

{

  __asm__( "out %%eax , %%dx" : : "a"( val ) , "d"( P ) ) ;

}

 

 

 

pciprobe.c

 

#include "..\include\pciprobe.h"

#include "..\include\port.h"

 

int PciBusProbe()  

{

unsigned int   dwInit     = 0x80000000;  //311, enable CONFIG_DATA

writel(CONFIG_ADDRESS,dwInit);

dwInit = readl(CONFIG_DATA);

if(dwInit == 0xFFFFFFFF)    //北桥 is not exist.

return 0;

return 1;

}

 

 

void PciProbe()    //bochsrc.bxrc里须加上pci: ..., slot1=ne2k才能检测到网卡

{

 unsigned int *ID = ( void * )0x400000 ;  //数据存于此,bochsdbg中用x/50 0x400000查看

 unsigned int   regVal;                  //0xCF8的写入值

 unsigned int   retVal;                   //0xCFC的读出值

 

  for (int busNo = 0; busNo < 2; busNo++) {                 // bus No

    for(int deviceNo = 0; deviceNo < 32; deviceNo++) {      // device no

      for (int funcNo = 0; funcNo < 8; funcNo++) {          // Function No

        regVal = 0x80000000                            // bit31 使能

                 + (busNo << 16)                        // Bus No

                 + (deviceNo << 11)                     // Device No

                 + (funcNo << 8);                       // Function No

 

        writel(0xCF8, regVal);

        retVal = readl(0xCFC);                         // 得到配置空间偏移为0的双字

        if (retVal != 0xffffffff) {                    // 设备存在

          *( ID ) = regVal;                              //存入regVal

          ID += 1;                                         //地址指针指向下一个双字

          *(ID ) = retVal;                              //存入retVal

          regVal += 0x08;                               // 得到配置空间偏移为08H的双字

          ID += 1;                                       

          *(ID ) = regVal;                              //存入retVal

          writel(0xCF8, regVal);

          retVal = readl(0xCFC);

          ID += 1;                                       

          *(ID) = retVal;                               //再次存入retVal

          if (funcNo == 0) {                            // 如果是单功能设备,则不再查funcNo>0的设备

            regVal = (regVal & 0xFFFFFFF0) + 0x0C;   //+1100,寄存器号为3

            ID += 1;                                      

            *(ID ) = regVal;                            //存入retVal

            writel(0xCF8, regVal);

            retVal = readl(0xCFC);

            ID += 1;                                  

            *(ID ) = retVal;                            //存入retVal

            retVal = retVal >> 16;

            if ((retVal & 0x80) == 0) funcNo = 8;       //1000 0000 , 如果最高位为0 ,跳出此轮循环

          }

        }

        ID += 1;                                       

        writel(0xCF8, 0);                                 //关闭使能位

      }

    }

  }

}

 

void netcardprobe()  //根据pciprobe检测出来网卡得到数据(比如0x80298086 ),在这里探测网卡的更多信息

{

 unsigned int *ID = ( void * )0x400120 ;  //数据存于此,bochsdbg中用x/50 0x400120查看

 unsigned int   regVal;                        //0xCF8的写入值

 unsigned int   retVal;                        //0xCFC的读出值

 unsigned short P ;                            //网卡端口

  

 

regVal = 0x80001000;    //此数值由pciprobe运行得来,手动更改,对应网卡,bochs环境下是0x80001000

writel(0xCF8, regVal);

retVal = readl(0xCFC);                      // 得到配置空间偏移为0的双字,vendorID,deviceID

 *( ID ) = regVal;                           //存入regVal

ID += 1;                                     

*(ID ) = retVal;                              //存入retVal

ID += 1;        

 

 

//下面是得到IO空间基址,regVal+0x10

writel(0xCF8,regVal+0x10 );            

retVal = readl(0xCFC);                     // 得到配置空间偏移为0x10的双字,bochs对应0xc041

*( ID ) = regVal+0x10;                     //存入regVal

ID += 1;                                     

*( ID ) = retVal;                       

P = retVal&0xfffc;                    //retVal最后两位清零,就是网卡IO空间基址,bochs结果 0xc040

 

 

//mac

unsigned char *ma = (unsigned char *) ID;

for(int i = 0; i < 14; i++){   //每次读出一个字节

  retVal = readb( P +0x10);

*(ma) = retVal;   //按字节存放

ma += 1;         

} 

writel(0xCF8, 0);                                 //关闭使能位

}

 

 

 

 

 

graph.h

#ifndef _GRAPH_H_

#define _GRAPH_H_

 

 

// 色调合成函数

unsigned short rgb_mix( unsigned char r , unsigned char g , unsigned char b ) ;

 

// 画点函数

void draw_dot( unsigned int x , unsigned int y , unsigned short color ) ;

 

// 显示英文

void ya_draw_english( unsigned int x , unsigned int y , unsigned int pos_in_font , unsigned short color ) ;

 

// 显示汉字

void ya_draw_chinese( unsigned int x , unsigned int y , unsigned int pos_in_font , unsigned short color ) ;

 

// 显示字符串

void ya_draw_chars( int x, int y, char *chars , unsigned short color) ;

 

 

// 显示四位bmp图片

void ya_draw_4bit_bmp( unsigned int x , unsigned int y ,unsigned int addr) ;

 

//画块,旋转

void draw_trunk(int addr_begin, int x, int y, int a, int b, unsigned short color) ;

 

#endif

 

 

 

 

port.h

#ifndef _PORT_H_

#define _PORT_H_

 

unsigned char readb( unsigned short p ) ;

 

unsigned short readw( unsigned short p ) ;

 

unsigned int readl( unsigned short p ) ;

 

 

void writeb( unsigned short p , unsigned char val ) ;

 

void writew( unsigned short p , unsigned short val ) ;

 

void writel( unsigned short p , unsigned int val ) ;

 

#endif

 

 

 

pciprobe.h

 

#ifndef _PCIPROBE_H_

#define _PCIPROBE_H_

 

#define CONFIG_ADDRESS       0xCF8    //Configure register used to read configure space. PCI的地址寄存器IO地址

#define CONFIG_DATA          0xCFC    //Data register.  PCI的数据寄存器IO地址

 

int  PciBusProbe();

void PciProbe() ;

void netcardprobe() ;

 

 

#endif

 

 

 

 

 

makefile

######################

#声明要编译的所有组成,这里的ya是本工程名称,可以取任何名字,这里就用ya

######################

ya:out/boot.bin out/kernelloader.bin out/kernel.asmo out/kernel.o out/graph.o out/port.o out/pciprobe.o out/kernel.ld  out/kernel.bin out/creat_img.exe out/write_in_img.exe A B C D E F G H

#开始对各部分编译,注意不是空格是Tab

out/boot.bin:code/boot.asm

nasm code/boot.asm -o out/boot.bin

out/kernelloader.bin:code/kernelloader.asm

nasm code/kernelloader.asm -o out/kernelloader.bin

# 编译asm文件,生成中间文件

out/kernel.asmo:code/kernel.asm

nasm -f aout code/kernel.asm -o out/kernel.asmo

# 编译C文件,生成中间文件

out/kernel.o:code/kernel.c

gcc -fpack-struct -std=c99 -c code/kernel.c -o out/kernel.o

out/graph.o:code/graph.c

gcc -fpack-struct -std=c99 -Wno-packed-bitfield-compat -c code/graph.c -o out/graph.o

out/port.o:code/port.c

gcc -fpack-struct -std=c99 -Wno-packed-bitfield-compat -c code/port.c -o out/port.o

out/pciprobe.o:code/pciprobe.c

gcc -fpack-struct -std=c99 -Wno-packed-bitfield-compat -c code/pciprobe.c -o out/pciprobe.o

# 链接内核

out/kernel.ld:out/kernel.asmo out/kernel.o out/graph.o out/port.o out/pciprobe.o

ld  -Ttext 0x80000 -e start -o out/kernel.ld out/kernel.asmo out/kernel.o out/graph.o out/port.o out/pciprobe.o

# 生成可执行代码文件

out/kernel.bin:out/kernel.ld

objcopy -R .note -R .comment -S -O binary out/kernel.ld out/kernel.bin

# 制作内核映象文件

out/creat_img.exe:code/creat_img.c

gpp code/creat_img.c -o out/creat_img.exe

# 执行dos命令,在final目录下生成a.img文件

A:

out/creat_img.exe final/a.img

 

# 写入文件,argv[1]=目标文件 argv[2]=源文件  argv[3]=写入偏移量  

#DOS下用法: write.exe a.img kernelloader.bin 512

out/write_in_img.exe:code/write_in_img.c

gpp code/write_in_img.c -o out/write_in_img.exe

# 执行dos命令,向a.img写入代码,内容是boot.bin

# 写入磁盘位置从0偏移量起始,1个扇区512字节

B:

out/write_in_img.exe final/a.img out/boot.bin 0

# 执行dos命令,向a.img写入代码,内容是kernelloader.bin

# boot.bin已经占用了512字节,写入磁盘位置从512偏移量起始,2个扇区1024字节

C:

out/write_in_img.exe final/a.img out/kernelloader.bin 512

# 执行dos命令,向a.img写入代码,内容是asc16

# boot.bin+kernelloader.bin已经占用了512+1024 = 1536字节,写入磁盘位置从1536偏移量起始

D:

out/write_in_img.exe final/a.img charpic/asc16 1536

E:

out/write_in_img.exe final/a.img charpic/hzk16f 5632

F:

out/write_in_img.exe final/a.img charpic/ya.bmp 267776

G:

out/write_in_img.exe final/a.img charpic/faya.bmp 361984

H:

out/write_in_img.exe final/a.img out/kernel.bin 479232

 

 

######################

 

 

 

 

0 0
原创粉丝点击