lab11 net

image-20230830133205600

background

  1. 在开始写代码之前,回顾一下xv6book的第五章会有帮助
  2. 你将使用E1000去处理网络通信
    1. E1000会和qemu模拟的lan通信
    2. 在qemu模拟的lan中
      1. xv6的地址是10.0.2.15
      2. qemu模拟的计算机的地址是10.0.2.2
  3. qemu会将所有的网络包都记录在packets.pcap
  4. 文件kernel/e1000.c包含了E1000的初始化代码,以及你需要补充的接收和发送的空函数
  5. kernel/e1000_dev.h包含了寄存器和标志位的定义
  6. kernel/net.ckernel/net.h包含了一个简单的内核栈去实现IP,UDP,ARP协议。这些文件也包含了一个灵活的数据结构去持有packet,叫作mbuf

your job

  1. 完成kernel/e1000.c中的e1000_transmit()e1000_recv()

简单捋一下实验的思路

  1. 首先,我们要修改的是设备驱动,也就是内核层面的代码,它会和硬件设备协同完成数据包的发送和接受
  2. 发送数据包时
    1. 内核只需要将已经准备好的mbuf放到一个缓冲数组中,就完事了。这就是缓冲数组的优点,我往里面一扔就行了
    2. 网卡中应该也有固定的程序,它会自己讲缓冲数组的数据包给发送出去
    3. 我们只需要完成1中的任务,网卡那边不需要我们管
  3. 接受数据包时
    1. 当网卡接收了数据时,它会将它存入另一个缓冲数组,存好之后它们通过一个中断,告诉内核来收数据了
    2. 内核只需要将这个缓冲数组中已经到达的数据包传递给上层应用即可

以上就是基本的交互框架,但是因为设备驱动是内核,是纯软件,而网卡设备是硬件,所以双方的交互就有点麻烦。这里通过了一个很神奇的操作,就是寄存器映射,将硬件的寄存器给映射到了内核的地址空间中,我们访问内核的某个地址,就是在访问硬件的寄存器,这一下子就打通了内核和硬件之间的桥梁

e1000_init中,就将寄存器映射的起始地址赋值给了regs,并且将各种信息和地址都存放到寄存器中,比如数组tx_ring的地址就放到了regs[E1000_TDBAL] = (uint64)tx_ring;

至此,准备工作就做完了,我们现在就需要增加内核代码,使其能够和网卡配合,完成数据报的发送和接受

hints:e1000_transmit

这个lab很有意思,它的hints基本就是给了你所有的伪代码,你一个一个去实现就行了

  1. 首先,让我们通过E1000_TDT为索引去regs取出当前的index,其中regs就是一个uint类型的数组的头指针
  2. 判断这个index指向的buf的状态,通过这个index去tx_ring中取出des,状态就存于des里的status中。这里要和一个宏E1000_TXD_STAT_DD相与进行判断
  3. 如果这个buf还存着之前的值,将它通过mbuffree给free掉
  4. 按提示修改des的各种参数,并且当前buf修改为传入的参数m即可。其中des的cmd参数没有给出提示,估计是想让我们自己查手册,我直接抄了大佬的E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS
  5. 最后,更新寄存器的值(空闲buf的指针,也就是第1步取出来东西的那个寄存器)

这里有个注意点就是,需要在函数首尾加锁。因为同一时刻,可能有多个进程想要通过网卡发送数据,这就形成了竞争的问题

int e1000_transmit(struct mbuf *m) {
    //
    // Your code here.
    //
    // the mbuf contains an ethernet frame; program it into
    // the TX descriptor ring so that the e1000 sends it. Stash
    // a pointer so that it can be freed after sending.
    //
    acquire(&e1000_lock);

    uint32 index = regs[E1000_TDT];
    struct tx_desc *des = &tx_ring[index];

    if (!(des->status & E1000_TXD_STAT_DD)) {
        release(&e1000_lock);
        return -1;
    }

    if (tx_mbufs[index]) {
        mbuffree(tx_mbufs[index]);
    }

    des->addr = (uint64)m->head;
    des->length = m->len;
    des->cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS;
    tx_mbufs[index] = m;

    regs[E1000_TDT] = (regs[E1000_TDT] + 1) % TX_RING_SIZE;

    release(&e1000_lock);
    return 0;
}

hints:e1000_recv

  1. 首先通过寄存器中E1000_RDT的值+1对RX_RING_SIZE取模获取待接收数据的索引
  2. 判断这个索引指向的buf的状态是否是待接收
  3. 如果是待接收,修改m->len并且通过net_rx将这个buf传递给上层
  4. 通过mbufalloc在这个索引处再次新建一个buf,并且将这个buf的des的data指针指向这个buf的head,然后将状态设置为0
  5. 最后将这个索引的寄存器的值+1,

这里有两个注意点

  1. 不需要加锁,因为这里给出了提示。如果这个函数没有运行完,那么不会产生另一个中断
void e1000_intr(void) {
    // tell the e1000 we've seen this interrupt;
    // without this the e1000 won't raise any
    // further interrupts.
    regs[E1000_ICR] = 0xffffffff;

    e1000_recv();
}
  1. 需要使用while循环,把能读的数据包都读出来。我猜是因为一次中断不一定代表只有一个数据包到了,甚至在处理中断的过程中,还会有数据包到。如果每次中断只读一个,会导致丢很多包
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个基于PyTorch和LAB色彩空间的黑白图片彩色化代码: ```python import torch import torch.nn as nn import torch.optim as optim from torch.autograd import Variable from torchvision import datasets, transforms from PIL import Image import numpy as np # 定义转换器,将PIL图像转换为张量,并将图像归一化到[-1,1]之间 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) # 定义数据集 train_data = datasets.ImageFolder('path/to/folder', transform=transform) # 创建数据加载器 train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True) # 定义网络结构 class ColorNet(nn.Module): def __init__(self): super(ColorNet, self).__init__() self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1) self.conv2 = nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1) self.conv3 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1) self.conv4 = nn.Conv2d(128, 128, kernel_size=3, stride=2, padding=1) self.conv5 = nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1) self.conv6 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1) self.conv7 = nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1) self.conv8 = nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1) self.conv9 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1) self.conv10 = nn.Conv2d(512, 512, kernel_size=3, stride=2, padding=1) self.conv11 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1) self.conv12 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1) self.conv13 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1) self.conv14 = nn.Conv2d(512, 512, kernel_size=3, stride=1, padding=1) self.conv15 = nn.Conv2d(512, 512, kernel_size=3, stride=2, padding=1) self.fc1 = nn.Linear(512 * 7 * 7, 4096) self.fc2 = nn.Linear(4096, 4096) self.fc3 = nn.Linear(4096, 1000) self.fc4 = nn.Linear(1000, 256 * 8 * 8) self.deconv1 = nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1) self.deconv2 = nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1) self.deconv3 = nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1) self.deconv4 = nn.ConvTranspose2d(32, 2, kernel_size=4, stride=2, padding=1) def forward(self, x): x = nn.functional.relu(self.conv1(x)) x = nn.functional.relu(self.conv2(x)) x = nn.functional.relu(self.conv3(x)) x = nn.functional.relu(self.conv4(x)) x = nn.functional.relu(self.conv5(x)) x = nn.functional.relu(self.conv6(x)) x = nn.functional.relu(self.conv7(x)) x = nn.functional.relu(self.conv8(x)) x = nn.functional.relu(self.conv9(x)) x = nn.functional.relu(self.conv10(x)) x = nn.functional.relu(self.conv11(x)) x = nn.functional.relu(self.conv12(x)) x = nn.functional.relu(self.conv13(x)) x = nn.functional.relu(self.conv14(x)) x = nn.functional.relu(self.conv15(x)) x = x.view(-1, 512 * 7 * 7) x = nn.functional.relu(self.fc1(x)) x = nn.functional.dropout(x, p=0.5) x = nn.functional.relu(self.fc2(x)) x = nn.functional.dropout(x, p=0.5) x = nn.functional.relu(self.fc3(x)) x = nn.functional.dropout(x, p=0.5) x = nn.functional.relu(self.fc4(x)) x = x.view(-1, 256, 8, 8) x = nn.functional.relu(self.deconv1(x)) x = nn.functional.relu(self.deconv2(x)) x = nn.functional.relu(self.deconv3(x)) x = nn.functional.tanh(self.deconv4(x)) return x # 定义损失函数和优化器 net = ColorNet() criterion = nn.MSELoss() optimizer = optim.Adam(net.parameters(), lr=0.001) # 训练网络 for epoch in range(10): running_loss = 0.0 for i, data in enumerate(train_loader): inputs, _ = data lab = np.zeros((inputs.shape[0], 3, 64, 64)) for j in range(inputs.shape[0]): img = inputs[j].numpy().transpose((1, 2, 0)) lab[j] = np.array(Image.fromarray((img + 1) / 2 * 255).convert('LAB'))[..., 1:] lab[j] /= 128 inputs = torch.from_numpy(lab[:, np.newaxis, :, :]).float() inputs, _ = Variable(inputs), Variable(inputs) optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, inputs) loss.backward() optimizer.step() running_loss += loss.data[0] if i % 10 == 9: print('[%d, %5d] loss: %.6f' % (epoch + 1, i + 1, running_loss / 10)) running_loss = 0.0 print('Finished Training') # 保存模型 torch.save(net.state_dict(), 'path/to/save/model.pth') ``` 在上面的代码中,我们定义了一个名为`ColorNet`的卷积神经网络,它接受L通道的灰度图像,并输出AB通道的彩色图像。我们使用MSE损失函数和Adam优化器来训练网络。 在训练过程中,我们将输入图像转换为LAB色彩空间,并将L通道作为网络的输入。在每个训练迭代中,我们计算网络的输出与输入之间的MSE损失,并使用反向传播来更新网络的权重。最终,我们保存了训练好的模型。 在使用训练好的模型进行彩色化时,我们可以将灰度图像转换为LAB色彩空间,并将L通道输入到网络中。网络输出的AB通道可以与原始L通道合并为彩色图像。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值