One last experiment, the code is on Github.

This experiment is actually quite simple, is to achieve the network card e1000_TRANSMIT and E1000_RECv functions. But look at the previous experiment seems to realize the upper socket related code, this year only network card driver.

Although there is a network card document with more than 400 pages in the experimental document, in fact, there is no need to read this thick document. The experimental hints make it very clear.

The experiment

E1000_TXD_CMD_R and E1000_TXD_CMD_EOP are only given in the macro definition of E1000_TXD_CMD_EOP. That means we only have to focus on these two:

int
e1000_transmit(struct mbuf *m)
{
  acquire(&e1000_lock);

  uint32 idx = regs[E1000_TDT];
  struct tx_desc* desc = &tx_ring[idx];

  if((desc->status & E1000_TXD_STAT_DD) == 0){
    release(&e1000_lock);
    printf("buffer overflow\n");
    return - 1;
  }

  if(tx_mbufs[idx])
    mbuffree(tx_mbufs[idx]);
  
  desc->addr = (uint64)m->head;
  desc->length = m->len;
  desc->cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP;
  tx_mbufs[idx] = m;

  regs[E1000_TDT] = (idx + 1) % TX_RING_SIZE;
  __sync_synchronize();
  release(&e1000_lock);
  return 0;
}
Copy the code

The e1000_recv function is used to query data in hints. If the e1000_recv function is used to query data in hints, the e1000_recv function is used to query data in hints.

static void
e1000_recv(void)
{
  int idx = (regs[E1000_RDT] + 1) % RX_RING_SIZE;
  struct rx_desc* desc = &rx_ring[idx];

  while(desc->status & E1000_RXD_STAT_DD){
    acquire(&e1000_lock);

    struct mbuf *buf = rx_mbufs[idx];
    mbufput(buf, desc->length);
    
    rx_mbufs[idx] = mbufalloc(0);
    if(! rx_mbufs[idx]) panic("mbuf alloc failed");
    desc->addr = (uint64) rx_mbufs[idx]->head;
    desc->status = 0;

    regs[E1000_RDT] = idx;
    __sync_synchronize();
    release(&e1000_lock);

    net_rx(buf);
    
    idx = (regs[E1000_RDT] + 1) % RX_RING_SIZE; desc = &rx_ring[idx]; }}Copy the code

conclusion

At this point, the entire XV6 experiment is done, written in time for the New Year. It has to be said that the experimental design of foreign countries is really good, the amount of code of the experiment is not large, each experiment is a few functions, the difficulty of the experiment is also set very appropriate. Eleven experiments finished, supporting the handout after reading the XV6 kernel most of the content are finished, for the core part of the operating system through the experiment have a more in-depth understanding. You know the difference between thread and process switching and how context switching works; From the concept of page table in the past to now I know how the whole paging mechanism works, and I have realized COW fork, MMAP, lazy allocation and other technologies based on paging and page missing exceptions. You learned how system calls are implemented and how the operating system works with the hardware to handle system calls and interrupt traps.

All in all, it is highly recommended that after learning operating system system, the experiment of this course will deepen and consolidate the understanding, rather than just stay in the textbook concepts, and have no contact with the actual kernel code. XV6 kernel implementation is very simplified, but all the core functions are realized, and the compilation speed is fast, and does not need a lot of configuration, compared with the Linux kernel is more suitable for beginners to learn, in the handout also introduced a lot of compared to Linux can be improved.