操作系统与网络实现 之十九(丁)

本文介绍了一种在自制操作系统中实现ICMP发送的方法,详细讲述了如何通过ne2k兼容网卡配置远程DMA读写,并利用汇编语言完成数据包构造及发送过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面是网卡发送ICMP(模拟ping 命令)

niclist查看我的真实网卡并在bochsrc.bxrc中写入:

ne2k:enabled=1,mac=b0:c4:20:A1:3C:00,ethmod=win32, ethdev=\Device\NPF_{B59B6CEB-251D-46D7-8778-EBAC0CAACC7D}

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

 

汇编中定义连续16进制数值还是有点麻烦,不像字符类型:

b1db 'kjsdvosierg'

数值型是这样子(用数组):

b2 db 0a1h,0bch,0efh,23h......  在内存中连续排列

这样是不行的:

b3 db 0x123456789abcdef

取值 b2[1]    这是一般的汇编,nasm不一样,在nasm里如果写成:

mov al,b2[5]  是错误的。

 

在这里耽搁了很长时间,总是提示编译错,找各种资料没解决,最后看了nasm使用手册,发现nasm与一般汇编不一样,它的数组是这样取值的:

[b2+0]  表示数组一,数组下标从0开始

mov bx,1

[b2+bx]   表示数组二  这是一般情况

 

但是在我的os程序里要这样子:

mov ebx,1

[b2+ebx]   表示数组二

否则出现:relocation truncated to fit: 16 against `.data'+ffffffa4

 

 

而对于数据包头的赋值,可以用nasm汇编里的structure更合适。

struc   tBIOSDA

        .COM1addr       RESW    1

        .COM2addr       RESW    1

        ; ..and so on

endstruc

 

 

 

mov cx,2         ;;循环 次

mov ebx,0

mov dx,ioNo+0x10  ;;远程DMA读写端口

next2:

mov al,[ns+ebx]

out dx,al         ;;依次写入到网卡rom 0x4000

inc ebx

dec cx         

jnz next2        ;;cx不为0则继续

其中dec cx一定要在这个位置,如果是这样

dec cx 

inc ebx

jnz next2

那么jnz是检测上一个语句是否为0,这里是inc ebx不为0,下一步cx-1的结果是cx值变为0xffff,陷入循环循环再循环

 

ne2000兼容网卡中

远程DMA(remote DMA)是指主机与网卡ram的读写,本地DMAlocal DMA)是指网卡对网卡ram的读(就是发送出去网络数据包)写(就是收到网络数据包)

ne2000兼容网卡编程中

偏移量 页面0             一般初始化值    

0x01   PSTART                

0x02   PSTOP                 

0X03   BNRY                  

0X04   TPSR   传输页开始      0x40

 

 

写入网卡缓冲区程序片段

;;之后启动远程DMA,数据写入RTL8019ASRAM0x4000,再启动本地DMA,将数据发送网上。

首先要指定写到什么地方

mov dx,ioNo+0x08

mov al,0x00       ;;RSAR0寄存器为远程开始地址低8

out dx,al

mov dx,ioNo+0x09

mov al,0x40       ;;RSAR1寄存器为远程开始地址高8

out dx,al

 

然后置CR命令寄存器的Bit3~5:

      001=远程DMA读        ->0x08

      010=远程DMA写        ->0x10

这里是写 

用来配合0x10处的远程DMA端口inout的指令,也就是多加一道开关,在我看来有点多此一举,而且近来是否有改进,不用设置此位也可以直接在0x10进行inout

mov dx,ioNo     

mov al,0x12       ;;远程DMA写页面0开始

out dx,al

以上两步准备好后可以inout了,其实在其它古老的程序中还有一段程序,我这里没用也能正常运行,那就是还要用寄存器0x0a远程字节计数RBCR0 0x0b远程字节计数RBCR1指定读写的字节数,

 

mov cx,20         ;;循环 次

mov ebx,0

mov dx,ioNo+0x10  ;;远程DMA读写端口

next2:

mov al,[ns+ebx]

out dx,al         ;;依次写入到网卡rom 0x4000

inc ebx

dec cx

jnz next2        ;;cx不为0则继续

注意经过写操作后其内部指针也变了,如果想要验证是否写入了数据,直接就读操作,那么读出来的数据是写入后的数值(全为0),所以要想读这些数据,还要加上前两步,指定位置和CR置位读

这样子

mov dx,ioNo+0x08

mov al,0x00       ;;RSAR0寄存器为远程开始地址低8

out dx,al

mov dx,ioNo+0x09

mov al,0x40       ;;RSAR1寄存器为远程开始地址高8

out dx,al

 

mov dx,ioNo

mov al,0xa       ;;远程DMA读页面0开始 进

out dx,al

 

mov cx,20       ;;循环 次

mov dx,ioNo+0x10  ;;CR命令寄存器

next:

in al,dx         ;;从网卡中依次读取

stosb           ;;并存放在ES:DI指向的缓冲区

dec cx

jnz next        ;;cx不为0则继续

 

 

 

 

最后发送时这样:

;;将数据写入0x4000就可以发送了,之后启动远程DMA,数据写入RTL8019ASRAM,再启动本地DMA,将数据发送网上。

mov dx,ioNo+0x08

mov al,0x00       ;;RSAR0寄存器为远程开始地址低8

out dx,al

mov dx,ioNo+0x09

mov al,0x40       ;;RSAR1寄存器为远程开始地址高8

out dx,al

 

mov dx,ioNo+0x04

mov al,0x40       ;;TPSR 发送页的起始页地址,初始化为指向第一个发送缓冲区的页即0x40

out dx,al

 

不同于remote DMA,下面这一步发送字节也很重要,不然bochs显示:

CR write -tx start tx bytes==0  不发送

 

mov dx,ioNo+0x05

mov al,0x62       ;;TBCR0 发送字节计数 98字节,低八位

out dx,al

mov dx,ioNo+0x06

mov al,0x00       ;;TBCR1 发送字节计数器,高八位

out dx,al

 

mov dx,ioNo

mov al,0x16       ;;远程DMA写,页面0,网卡加电,发送

out dx,al

最后这个0x16远程DMA写虽然不对,不过不影响发送

 

201509151409分发送成功

wps165.tmp

 

IP 192.168.1.99正是我们的网卡IP地址 ICMP是我们发送的ping

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值