Replies: 24 comments 7 replies
-
Beta Was this translation helpful? Give feedback.
-
dw 网卡驱动运行后,中断报错接受 buffer 不可用 |
Beta Was this translation helpful? Give feedback.
-
参考陈乐同学之前在ArceOS上的工作把cvitek-nic的框架搭建好了, |
Beta Was this translation helpful? Give feedback.
-
MAC寄存器组 与 DMA寄存器组:
这些寄存器组的具体细节和功能可能因不同的以太网控制器而有所不同。在进行以太网控制器编程时,你需要查阅硬件厂商提供的文档,了解具体的寄存器布局和功能,以便正确地配置和操作以太网控制器。 |
Beta Was this translation helpful? Give feedback.
-
网卡驱动技术实现: |
Beta Was this translation helpful? Give feedback.
-
Dwmac介绍 "DWmac" 是指 "DesignWare MAC",它是Synopsys公司推出的一种网络接口控制器IP(Intellectual Property),用于在嵌入式系统中实现以太网(Ethernet)功能。DWmac IP是用于集成到SoC(System on Chip)中的一个IP核,帮助系统在物理层和数据链路层实现以太网通信。 DWmac提供了一个高度可配置和可定制的以太网MAC控制器,可以适配不同的以太网标准和速率。它支持多种操作模式和功能,例如全双工和半双工传输、自动重传请求(ARQ)、流控制等,以支持数据在网络中的可靠传输。 DWmac通常用于嵌入式系统中,这些系统可能包括嵌入式处理器、FPGA(Field-Programmable Gate Array)等。它为这些系统提供了可靠的网络连接功能,使得设备能够通过以太网与其他设备或网络进行通信。 总之,DWmac是一种以太网控制器IP,由Synopsys公司提供,用于嵌入式系统中实现以太网通信功能。这是一种常见的解决方案,用于在嵌入式系统中集成网络连接能力。 |
Beta Was this translation helpful? Give feedback.
-
PHY芯片 与 DWMAC 的关系?
关系: |
Beta Was this translation helpful? Give feedback.
-
实现网卡驱动的两个关键的步骤:
|
Beta Was this translation helpful? Give feedback.
-
DMA映射是什么? DMA映射(DMA Mapping)是一种将内存区域与外部设备之间建立映射关系的过程,以便直接内存访问(DMA)控制器能够在设备和内存之间高效地传输数据,而无需CPU的干预。这种技术允许数据在设备和内存之间进行快速、无缝的传输,提高了系统性能和数据传输效率。 DMA映射通常涉及以下步骤:
总之,DMA映射是一种通过建立内存和外部设备之间的映射关系,实现高速数据传输的技术。这在需要大量数据传输的应用中特别有用,可以显著提高系统性能和数据传输效率。 |
Beta Was this translation helpful? Give feedback.
-
网卡工作原理 1、网卡的基本机构 网卡包含7个功能模块分别是:
数据发送路径:OB->LC->TX 参考:《网络知识:网卡的基本组成结构和工作原理》 https://zhuanlan.zhihu.com/p/564901837 |
Beta Was this translation helpful? Give feedback.
-
Ethernet MAC(Media Access Control)是以太网中的数据链路层的一个子层,负责控制和管理数据在局域网内的传输。它定义了数据帧的格式、数据的传输方式、帧的生成和解析规则等,以确保多台设备可以在共享的物理媒介上进行有效的通信。 以太网MAC层的主要功能包括:
Ethernet MAC层通常与PHY(Physical Layer)层紧密合作,PHY层负责将数据帧转换为适合在物理媒介上传输的信号,并将接收到的信号转换回数据帧。这两个层级协同工作,实现了以太网通信的各个方面,从数据生成到传输再到接收。 |
Beta Was this translation helpful? Give feedback.
-
华山派 Ethernet PHY 蕊片供一组内建 Ethernet 10/100 Base-TX compliant PHY 接口。 功能描述:
10/100Mbps 传送及收发功能在标准 category5(CAT5) 双绞线上, 传送接收讯号经由 |
Beta Was this translation helpful? Give feedback.
-
华山派 ON ArceOS 网卡驱动框架搭建本文档记录在华山派( CV1811H )上搭建网卡驱动框架的流程 目前能成功初始化网卡并执行 helloworld app 在 qemu 模拟器上执行的结果如下图(选用aarch64 架构是因为我们为了适配华山派,修改了ArceOS 的页表项, 在Riscv64 架构下暂时不能在 qemu 上运行)。 make A=apps/net/cvitek_nic_test ARCH=aarch64 SMP=1 NET=y LOG=info run run in CV1811: make A=apps/net/cvitek_nic_test ARCH=riscv64 SMP=1 NET=y LOG=info cv1811 初探框架代码增添网卡驱动框架代码(与网卡驱动具体实现无关),需要做出一些改动: apps层
ulib层
modules层
crates层
其他文件
框架代码分析step 1After executed all initial actions, then arceos calls step 2fn http_server(mut stream: TcpStream) -> io::Result {
...
stream.read(&mut buf)?;
...
stream.write_all(reponse.as_bytes())?;
...
}
fn accept_loop() -> io::Result {
let (addr, port) = (IpAddr::from_str(LOCAL_IP).unwrap(), LOCAL_PORT);
let mut listener = TcpListener::bind((addr, port).into())?;
...
loop {
match listener.accept() {
Ok((stream, addr)) => {
task::spawn(move || match http_server(stream) {
Err(e) => error!("client connection error: {:?}", e),
Ok(()) => info!("client {} closed successfully", i),
});
}
Err(e) => return Err(e),
}
i += 1;
}
}
#[no_mangle]
fn main() {
println!("Hello, ArceOS HTTP server!");
accept_loop().expect("test HTTP server failed");
} step 2.1let (addr, port) = (IpAddr::from_str(LOCAL_IP).unwrap(), LOCAL_PORT);
let mut listener = TcpListener::bind((addr, port).into())?; flow chart graph TD;
T["libax::net::tcp::TcpStream::bind()"]
T-->A["smoltcp::wire::ip::IpAddr::from_str()"]
T-->B["axnet::smoltcp_impl::tcp::TcpSocket::new()"]
T-->C["axnet::smoltcp_impl::tcp::TcpSocket::bind()"]
T-->D["axnet::smoltcp_impl::tcp::TcpSocket::listen()"]
B-->E["axnet::smoltcp_impl::SocketSetWrapper::new_tcp_socket()"]
E-->F["axsync::mutex< smoltcp::iface::socket_set::SocketSet >"]
F-->G["managed::slice::ManagedSlice< smoltcp::iface::socket_set::SocketStorage >"]
G-->H["smoltcp::iface::socket_meta::Meta + smoltcp::socket::Socket"]
H-->I["SocketHandle + NeighborState"]
H-->J["Raw + Icmp + udp + tcp"]
D-->K["ListenTable: Box< [Mutex< Option< Box< ListenTableEntry > > >] >(tcp)"]
K-->L["ListenTableEntry: VecDeque< SocketHandle >(syn_queue)"]
L-->M["Tcp is a multi-wrapped sync queue of SocketHandle"]
step 2.2match listener.accept() {
Ok((stream, addr)) => {
...
}
Err(e) => return Err(e),
} flow chart graph TD;
T["libax::net::tcp::TcpListener::accept()"]
T-->A["axnet::smoltcp_impl::tcp::TcpSocket::accept()"]
A-->B["Mutex< SocketSet >.poll_interfaces()"]
B-->C["axnet::smoltcp_impl::InterfaceWrapper< axdriver::VirtIoNetDev >.poll"]
C-->Z["many things"]
A-->D["axnet::smoltcp_impl::listen_table::ListenTable::accept()"]
D-->E["check the sync queue"]
step 2.3stream.read(&mut buf)?;
stream.write_all(reponse.as_bytes())?; flow chart graph TD;
A["impl Read, Write for libax::TcpStream"] --> B["libax::TcpStream::read"]
A["impl Read, Write for libax::TcpStream"] --> C["libax::TcpStream::write"]
B --> D["smoltcp_impl::TcpSocket::recv(buf)"]
C --> E["smoltcp_impl::TcpSocket::send(buf)"]
可以看到现有ArceOS的网络部分使用了 smoltcp 这个项目, 为了兼容其实现,需要按照smoltcp 提供的 trait 来实现网卡驱动: https://github.com/rcore-os/smoltcp/blob/main/src/phy/mod.rs Access to networking hardware.
The `phy` module deals with the *network devices*. It provides a trait
for transmitting and receiving frames, [Device](trait.Device.html)
and implementations of it 按照如下的框架实现的网络设备即可和 smoltcp 兼容 impl Device for DeviceWrapper struct DeviceWrapper {
inner: RefCell<AxNetDevice>, // use `RefCell` is enough since it's wrapped in `Mutex` in `InterfaceWrapper`.
rx_buf_queue: VecDeque<RxBuf>,
} 而 AxNetDevice 会在初始化时和我们定义的网卡驱动设备绑定, 在这里 AxNetDevice 展开是这样的: pub type AxNetDevice = driver_net::cvitek::CvitekNic<CvitekNicTraitsImpl> /// modules/axdriver/src/macros.rs
macro_rules! register_net_driver {
($driver_type:ty, $device_type:ty) => {
/// The unified type of the NIC devices.
#[cfg(not(feature = "dyn"))]
pub type AxNetDevice = $device_type;
};
} 下面定义了需要实现的方法: /// crates/driver_net/src
/// Operations that require a network device (NIC) driver to implement.
pub trait NetDriverOps: BaseDriverOps 下面是方法的具体实现: crates/driver_net/src/cvitek/mod.rs
impl<A:CvitekNicTraits> NetDriverOps for CvitekNic<A> {
// 里面定义了网卡驱动需要实现的方法(NetDriverOps),
// 这些方法会被 modules/axnet/src/smoltcp_impl/mod.rs 调用并进一步封装,
// 同时这里会用到在crates/cvitek-nic/src/cvitek_main.rs 中提供的 CvitekNicDevice 的实现和其他一些辅助方法.
} pub struct CvitekNic<A>
where
A: CvitekNicTraits,
{
device: CvitekNicDevice<A>,
phantom: PhantomData<A>,
} 实现我们的 CvitekNic 设备还需要用到在 crates/cvitek-nic/crates/cvitek-nic/src/cvitek_main.rs实现的 CvitekNicDevice 结构和方法,这样就可以自由的编写我们网卡驱动的整体逻辑,最后只需要实现出方便调用的接口即可。 总体而言, 框架搭好后, 只需要实现自己的网卡驱动并且为其实现 NetDriverOps 特征即可。 有了框架以后, 实现网卡驱动需要修改的文件: // TODO! crates/driver_net/src/cvitek/mod.rs // 实现 NetDriverOps 特征 crates/cvitek-nic // 网卡驱动相关实现 参考实现: https://github.com/yuoo655/arceos // TODO! smoltcp代码分析 |
Beta Was this translation helpful? Give feedback.
-
Synopsys 手册 DWC Ether MAC 10/100/1000 Universal |
Beta Was this translation helpful? Give feedback.
-
华山派 cvitek 代码: |
Beta Was this translation helpful? Give feedback.
-
graph TB
ethernet_init
==>csi_eth_mac_phy_init
==> csi_eth_mac_initialize
==> csi_eth_phy_initialize
==> csi_eth_phy_initialize_complete
==> csi_eth_mac_connect_phy
==> csi_eth_mac_phy_enable
g_mac_phy_init_finish
==> csi_eth_mac_phy_init_Complete([csi_eth_mac_phy_init_Complete])
==> aos_task_new_ext["aos_task_new_ext(ð_hdl, 'eth_init',
eth_init_func, NULL, 8192,
AOS_DEFAULT_APP_PRI+1);"] --- taskCreate["一系列task create,
entry就是eth_init_func"]
==> eth_init_func-subgraph1
designware_eth_init --- regs_manipulation1["dma_reg manipulation
mac_reg manipulation"] -.-> rx_descs_init
regs_manipulation1 -.-> tx_descs_init --- tx_descs_init-step["转换handle参数成mac_dev指针
从mac_dev获取priv指针
从priv获取dma_regs指针
从priv获取tx_mac_descrtable[0]指针
从priv胡获取txbuffs[0]指针
struct dmamacdescr *desc_p;
(rx_descs_init里多了 Flush rxbuff)
循环tx_mac_descrtable 更新成员
desc_p->dmamac_addr 和 dmamac_next
(rx_descs_init里多了 dmamac_cntl 和txrx_status)
更新最后一个成员的next 形成环形
Flush all Tx buffer descriptors at once
更新dma_reg
dma_reg->txdesclistaddr = (unsigned long)&desc_table_p[0];
priv->tx_currdescnum = 0;"]
csi_eth_mac_phy_enable -.-> csi_eth_mac_control -.->|Step 1| designware_eth_start -.-> designware_eth_init
csi_eth_mac_phy_enable ==> csi_eth_mac_control ====>|step 5| designware_adjust_link === csi_eth_mac_phy_enable_Complete === g_mac_phy_init_finish
csi_eth_mac_phy_enable -.-> csi_eth_mac_control -..->|step 3|designware_eth_enable[designware_eth_enable TX and RX]
csi_eth_mac_phy_enable -..->|step 2| csi_eth_phy_power_control
csi_eth_mac_phy_enable -...->|step 4| csi_eth_mac_set_macaddr
csi_eth_mac_set_macaddr["csi_eth_mac_set_macaddr(handle,mac)"] -..- MemCopy2["gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
memcpy(mac_dev->mac_addr, mac->b,"]
-.->designware_write_hwaddr["designware_write_hwaddr(handle)"]
---|操作macaddr寄存器| MacID["mac_reg->macaddr0hi = macid_hi;
mac_reg->macaddr0lo = macid_lo;"]
csi_eth_phy_power_control -.call.- eth_phy_start -.call.-> phyStart["dev->start(handle)"] --> cv181x_start1
csi_eth_phy_initialize -. "call it to generate phy_dev" .-> eth_connect_phy["eth_connect_phy
ret phy_dev"] -->|"then call with phy_dev"| eth_phy_reset -- then --> eth_phy_config -- then ---> ret1["return phy_dev ptr"] --> csi_eth_phy_initialize_complete([csi_eth_phy_initialize_complete])
eth_connect_phy -.call.-> eth_config
eth_connect_phy-..->|then call|eth_get_phy_by_mask["eth_get_phy_by_mask
return phydev"] -.call.-> eth_read_phy_id
eth_get_phy_by_mask -->|return phy_dev pointer| eth_connect_phy
eth_phy_config -."call, passin handle/phy_dev".-> config["dev.config(handle)"] -.call.-> cv181x_config1
eth_get_phy_by_mask -..->|then call| eth_get_phy_device["ret eth_get_phy_device"] -->|get,update and ret| ss["eth_phy_devices[0]"] -->|it is cv181x_device| cv181x_device{{cv181x_device}} -->|cv181x_device.config函数指针指向_所谓connect|cv181x_config1
subgraph cv181x_config1
direction TB
cv181x_config-->|"一堆mmio_write_32 配置"| ConfigPHY -."call,传入参数dev/handle".->genphy_config1
end
subgraph genphy_config1
direction TB
genphy_config --> feature_config[一堆feature config] -.call.->eth_phy_read --> feature_config2[一堆feature config] -.最后call并返回0.-> genphy_config_aneg1
end
subgraph genphy_config_aneg1
direction TB
genphy_config_aneg -.call.->genphy_setup_forced
genphy_setup_forced -.nextcall.->genphy_config_advert
genphy_config_advert -.nextcall.->genphy_restart_aneg
end
cv181x_config1 o-.- ret1
csi_eth_mac_initialize -.-o csi_eth_mac_initialize1
subgraph csi_eth_mac_initialize1
direction TB
B["gmac_dev_t *mac_dev=&gmac_instance[idx]"] --> B3["给mac_dev.base/irq/cn_evenet赋值"] --> |"dw_gmac_priv *priv, *priv_unalign="|B2[memalign]
--- |DMA 区域清零|memset
---|mac regs pointer|priv.mac_regs_p
---|dma regs pointer|priv.dma_regs_p
---|将 priv和priv_unalign 保存到 mac_dev中| mac_dev.priv["mac_dev->priv = priv;"]
---request_irq
---|return|mac_dev
end
subgraph cv181x_start1
direction TB
cv181x_start --> genphy_update_link --"if not ret 0 then return"----> cv181x_parse_status["cv181x_parse_status(dev);
parse and save to priv"]
genphy_update_link -.eth_phy_read.-> return-fn_phy_read? --> csi_eth_mac_phy_read
end
subgraph eth_init_func-subgraph1
direction TB
eth_init_func
==> tcpip_init["lwip::tcpip::tcpip_init(initfunc, arg)"]
==> netif_add["lwip::netif_add(ð_xnetif, &ipaddr, &netmask,
&gw, NULL, ethif_init, tcpip_input);"]
-.-> nethif_init-subgraph1
netif_add
====> |Registers the default network interface.| netif_set_default
==>|"When the netif is fully
configured this function must be called."| netif_set_up
==> netif_set_status_callback
==> netmgr_dev_eth_init
==> event_service_init
==> netmgr_service_init
==> netifapi_dhcp_start
tcpip_init
-.-> lwip_inited{lwip_inited=1}
lwip_inited --> |Yes|initfunc["initfunc(arg) then return"]
lwip_inited ---> |No|lwip_init
-.-> stats_init
--> sys_init
--> mem_init
--> memp_init
--> pbuf_init
--> netif_init
--> ip_init
--> etharp_init
--> raw_init
--> udp_init
--> tcp_init
--> igmp_init
--> dns_init
--> ppp_init
--> sys_timeouts_init
lwip_init
--> sys_mbox_new
--> sys_thread_new["sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread,
NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);"]
-.-> tcpip_thread
-.-> tcpip_init_done
--> tcpip_timeouts_mbox_fetch["tcpip_timeouts_mbox_fetch(&tcpip_mbox, (void **)&msg)"]
--> tcpip_thread_handle_msg["tcpip_thread_handle_msg(msg)"]
end
subgraph nethif_init-subgraph1
direction TB
ethif_init
--> netif-setup["设置netif结构体的 hostname,output,
linkoutput, output_ip6 具体指向的函数"]
--> |initialize the hardware| low_level_init
-.call.-> setup2["设置netif结构体的hwaddr_len,
mtu, flags"]
--> |Create a task| eth_rx
-------> |Create a task| _eth_phy_update_link_task
eth_rx -.-> ethernetif_input -.-> low_level_input["p = low_level_input(netif)"]
-.-> netif-input["调用netif->input(p, netif)"]
-.- tcpip_input["lwip::tcpip_input"]
-.-> tcpip_inpkt["return lwip::tcpip_inpkt
(p, inp, ethernet_input);"]
_eth_phy_update_link_task
-.-> csi_eth_phy_get_linkstate
end
|
Beta Was this translation helpful? Give feedback.
-
华山派驱动开发目前共四个任务: |
Beta Was this translation helpful? Give feedback.
-
Reconciliation子层将MII映射到PLS服务原语 PLS服务原语对应的MII信号1、PLS_DATA.request(OUTPUT_UNIT)总共三个信号,1,0,以及DATA_COMPLETE,TXD的四位分别表示一个0或者1,从3-0,一个序列,当TX_EN置位的时候就传递这个信息,当TX_EN deassertion的时候传递DATA_COMPLETE消息。用TX_CLK传递同步消息。 TX_ER(transmit coding error)TXD<3:0>(transmit data)TX_EN(transmit enable)TX_CLK(transmit clock)这个是时钟信号,由PHY提供,因为TXD总共4位,所以,PHY提供的时钟信号应当是正常传输数据信号的1/4。比如100Mbps,就应当提供25MHz的一个信号。 这几个信号的组合有几种可能,然后会有不同的结果,具体见Table22-1(709页左右) 里面有个LPI的情况,感觉是低功耗状态(?) 2、PLS_SIGNAL.indicationCOL包括signal_error和no_signal_error col置位的时候表示error,反过来则no error COL也不需要同步,0.8寄存器位置位时,行为未指定 3、PLS_DATA.indication(INPUT_UNIT)这个只有0和1,由RXD四位表示,同样从3-0分别表示 RXD<3:0>(receive data)对RX_DV置位的每个RX_CLK指示的周期,将四位数据从PHY传输到reconciliation 子层。 RX_ERRX_CLK(receive clock)这个时钟信号同样由PHY提供,(因为接收数据的时钟并不完全对齐),所以PHY可以从接收的数据中回复RX_CLK基准,也可以从TX_CLK等时钟基准中获取RX_CLK时钟。 这里面没有了TX_EN,也就是说,传送这件事情需要有包结束信号,但是接收这件事情不需要。 同样的,和TX一样(在TX_EN不置位的时候),RX_DV不置位的时候,用于指示LPI等等相关信号。 4、PLS_CARRIER.indicationCRS包括两个信号: carrier_on和carrier_off 如果接收和发送介质非空闲,CRS应当由PHY置位,如果都空闲则取消。 这个信号不需要与TX_CLK或者RX_CLK同步 如果控制寄存器的0.8也就是双工模式位置位,或者自协商选择了全双工模式,那么CRS的行为未指定。 5、PLS_DATA_VALUE.indicationRX_DV(receive data valid)在帧接收的时候,RX_DV和RX_ER如果都置位了,那么会指示这个帧有一个FrameCheckError。 包括两个值:DATA_VALUE和DATA_NOT_VALUE 这个我看了感觉还用于指示一些同步的问题。 其他MDCMDC作为MDIO的时钟信号参考。 MDIOMDIO是PHY和STA之间的双向信号。 MII数据流数据包在MII上的传送应当具有以下的格式 < inter-frame >< preamble >< sfd >< data >< efd > 每个8位字节作为两个半字节进行发送和接收。 Inter-frame帧间周期不会发生任何数据活动,RX_DV信号取消和TX_EN信号取消置位表示不存在数据活动。 Preamble发送的情况,七个10101010 收包的情况,只能收到一个前导的10101011,这七个10101010没了。 SFD10101011 MDIOMDIO使用简单的双线串行接口,用于链接PHY并控制PHY,称为MII Management Interface 管理接口通过一对MII或者GMII传输的信号,帧格式和协议规范,以及通过这些帧读取和写入的寄存器集合组成。 MII使用两个基本寄存器,GMII使用了第三个。 MII基本寄存器 由两个寄存器组成,分别是控制寄存器(寄存器0)和状态寄存器(寄存器1) GMII在这俩之外还包括了寄存器15(扩展状态寄存器) 这个status和ctrl功能被认为是100Mbps和1000Mbps的基本功能。(也就是说,这三个寄存器才是最基本的) 寄存器2-14是扩展寄存器集合的一部分 寄存器4-10的格式是为了使用特定的自协商协议定义的。这些寄存器格式由寄存器1和15定义 寄存器具体而言,前16个寄存器0-15是有规定好功能定义的 后面16-31是厂家自己设计的。 (但是为什么在phy.h中对后面的寄存器也有呢???) 关于这16个寄存器,功能分别如下记录 使用X.Y方式记录,比如0.15就表示第0号寄存器的第15个bit。 这些寄存器都是16位的。 0号寄存器-Ctrl(MII和GMII下都是基本寄存器)
1号寄存器-Status(MII和GMII下都是基本寄存器)
这里对寄存器说明有Latching low和Latching high(不太懂翻译成中文是啥,但是说了全都是只读的) 2号寄存器-PHY_id3号寄存器-PHY_id2和3都是用来做这个的。2为高16位,3为低16位。 4号寄存器-Auto-Negotiation-Advertisement5号寄存器-Auto-Negotiation-Link-Partner-Base-Page-Ability6号寄存器-Auto-Negotiation-Expansion7号寄存器-Auto-Negotiation-Next-Page-Transmit8号寄存器-Auto-Negotiation-Link-Partner-Received-Next-Page9号寄存器-Master-Slave-Control-Register10号寄存器-Master-Slave-Status-Register上面的自动协商的寄存器看28.2.4.1和37.2.5.1 主从模式的9和10看32.5和40.5 11号寄存器-PSE-Ctrl-Register看33.5.1.1 12号寄存器-PSE-Status-Register33.5.1.2 13号寄存器-MMD-Access-Ctrl-Register
14号寄存器-MMD-Access-Address-Data-Register全都用来表示地址数据 15号寄存器-Extended-Status(GMII下是基本寄存器)
剩余寄存器-厂商自定义(好多呀。。。) |
Beta Was this translation helpful? Give feedback.
-
我这边phy驱动的框架也已经搭建好了,在张轩铬的基础上完成的 |
Beta Was this translation helpful? Give feedback.
-
目前ArceOS riscv 平台只启用了时钟中断(register和dispatch时 把 timer和其他中断做了区分)。
// modules/axhal/src/platform/qemu_virt_riscv/irq.rs
/// Enables or disables the given IRQ.
pub fn set_enable(scause: usize, _enabled: bool) {
if scause == S_EXT {
// TODO: set enable in PLIC
}
}
/// Dispatches the IRQ.
///
/// This function is called by the common interrupt handler. It looks
/// up in the IRQ handler table and calls the corresponding handler. If
/// necessary, it also acknowledges the interrupt controller after handling.
pub fn dispatch_irq(scause: usize) {
with_cause!(
scause,
@TIMER => {
trace!("IRQ: timer");
TIMER_HANDLER();
},
@EXT => crate::irq::dispatch_irq_common(0), // TODO: get IRQ number from PLIC
); // <<<<<<< 这里没有获取中断号,固定写成了0,时钟中断
} |
Beta Was this translation helpful? Give feedback.
-
dw_gmac_mars 代码平移到Rust的工作主要涉及了以下函数
|
Beta Was this translation helpful? Give feedback.
-
https://github.com/yuoo655/arceos_net 星光一代,星光二代网卡驱动仓库地址,找对应分支即可。 代码未整理,还比较乱 |
Beta Was this translation helpful? Give feedback.
-
https://github.com/yuoo655/arceos_net/tree/hsp 华山派网卡收发包功能完成. 没法再fork一次,目前是直接把zy的仓库代码复制过来修改 |
Beta Was this translation helpful? Give feedback.
-
我找到了个图片,感觉可以方便理解 |
Beta Was this translation helpful? Give feedback.
-
支持各种物理网卡,尽量做到与OS无关
如有兴趣一起来探索,请联系我 yuchen AT tsinghua.edu.cn OR 微信 id chyyuu
Beta Was this translation helpful? Give feedback.
All reactions