下面是网卡发送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进制数值还是有点麻烦,不像字符类型:
b1: db '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的读写,本地DMA(local DMA)是指网卡对网卡ram的读(就是发送出去网络数据包)写(就是收到网络数据包)
ne2000兼容网卡编程中
偏移量 页面0 一般初始化值
0x01 PSTART
0x02 PSTOP
0X03 BNRY
0X04 TPSR 传输页开始 0x40
写入网卡缓冲区程序片段
;;之后启动远程DMA,数据写入RTL8019AS的RAM的0x4000,再启动本地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端口in和out的指令,也就是多加一道开关,在我看来有点多此一举,而且近来是否有改进,不用设置此位也可以直接在0x10进行in和out
mov dx,ioNo
mov al,0x12 ;;远程DMA写页面0开始
out dx,al
以上两步准备好后可以in和out了,其实在其它古老的程序中还有一段程序,我这里没用也能正常运行,那就是还要用寄存器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,数据写入RTL8019AS的RAM,再启动本地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写虽然不对,不过不影响发送
2015年09月15日14点09分发送成功
IP 192.168.1.99正是我们的网卡IP地址 ICMP是我们发送的ping