Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Network implementation #355

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft

Network implementation #355

wants to merge 16 commits into from

Conversation

roblabla
Copy link
Member

@roblabla roblabla commented Jun 28, 2019

Let's talk to the internet!

test

Currently, virtio is able to talk to a TCP server. virtio is all hardcoded though, so what's left to do is:

  • Separate virtio into two services: virtio proper and virtio-net.
    • virtio is responsible for handling the generic virtio interface. All the virtio devices are owned by the virtio sysmodule, which will expose an IPC interface to interact with them (Feature negociation, setting up the virtqueues, pushing/popping buffers, waiting for an event, etc...)
    • virtio-net will contain the drivier for virtio-net interfaces, the glue to make it work with smoltcp, and expose an IPC interface bsd which will expose the BSD Socket interface we're all familiar with.
  • Implement the bsd interface on top of smoltcp. Smoltcp's interface is very different from the standard BSD socket, so we might need to do quite a bit of glue here.
  • Add a DHCP client for auto-discovery of the IP address and whatnot. This is integrated into the smoltcp master, but it requires quite a bit of code to get it set up.
  • Implement a "telnet"/netcat client in shell to test the implementation.
  • Oh yeah, originally, I did this to test the IOMMU. Might want to implement that too...

@todo
Copy link

todo bot commented Jun 28, 2019

iommu_platform=true

SunriseOS/Makefile.toml

Lines 246 to 256 in 32af349

# TODO: iommu_platform=true
"-device", "virtio-net,disable-legacy=on,netdev=u1", "-netdev", "user,id=u1",
# Dump packets going on the vlan
"-object", "filter-dump,id=f1,netdev=u1,file=dump.dat",
# Trace virtio-related events
"--trace", "virtio_set_status,file=trace", "--trace", "virtio_queue_notify,file=trace", "--trace", "virtio_notify,file=trace", "--trace", "virtio_input_queue_full,file=trace",
"--trace", "virtio_net_announce_notify,file=trace", "--trace", "virtio_net_announce_timer,file=trace", "--trace", "virtio_net_handle_announce,file=trace",
"--trace", "virtio_net_post_load_device,file=trace", "--trace", "virtio_notify_irqfd,file=trace",
]
[tasks.qemu-debug]


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

,iommu_platform=true

SunriseOS/Makefile.toml

Lines 273 to 283 in 32af349

# TODO: ,iommu_platform=true
"-device", "virtio-net,disable-legacy=on,netdev=u1", "-netdev", "user,id=u1",
# Dump packets going on the vlan
"-object", "filter-dump,id=f1,netdev=u1,file=dump.dat",
# Enable GDB
"-gdb", "tcp::${GDB_PORT}", "-S",
# Print state on CPU reset
"-d", "cpu_reset",
# Trace virtio-related events
"--trace", "virtio_set_status,file=trace", "--trace", "virtio_queue_notify,file=trace", "--trace", "virtio_notify,file=trace", "--trace", "virtio_input_queue_full,file=trace",


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Unmap the virt_addr

// TODO: Unmap the virt_addr
}
}
#[derive(Debug)]
pub struct MappedBARMemory64 {
phys_addr: u64,
virt_addr: *mut u8,
size: u64,
}


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Unmap the virt_addr

// TODO: Unmap the virt_addr
}
}
#[derive(Debug)]
pub enum MappedBAR {
Memory(MappedBARMemory),
Memory64(MappedBARMemory64),
Io(BARIo)
}


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

More interesting debug.

#[derive(Debug)] // TODO: More interesting debug.
pub struct MsiX<'a> {
inner: RWCapability<'a>
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct MsiXEntry {
pub addr: u64,
pub data: u32,
pub ctrl: MsiXControl


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Lazily read the Vendor-Specific Capabilities?

Currently, vendor-specific capabilities are eagerly read and kept in a vector. This is likely suboptimal. Ideally, we should get some type that we can call functions on to get u32s from.


/*// TODO: Lazily read the Vendor-Specific Capabilities?
// BODY: Currently, vendor-specific capabilities are eagerly read and kept in a
// BODY: vector. This is likely suboptimal. Ideally, we should get some type that
// BODY: we can call functions on to get u32s from.
let mut size = word.get_bits(16..24) as u8;
let mut data = Vec::with_capacity(size.saturating_sub(3) as usize);
let mut idx = 4u8;
data.push(word.get_bits(24..32) as u8);
while idx < size {
let word = pci_config_read_word(bus, slot, function, register + idx);


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

DMAR

// TODO: DMAR
addr: 0xFEE0_0000,
data: 0x0000_0033,
ctrl: MsiXControl(0)
};
self.device.set_msix_message_entry(0, entry).unwrap();
self.queues.clear();
for i in 0..self.common_cfg.num_queues() {
self.queues.push(None)
}


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Schedule out?

// TODO: Schedule out?
}
}
/// 4.1.5.1.3 Virtqueue Configuration
pub fn setup_virtqueue(&mut self, virtqueue_idx: u16) {
let mut queue = self.common_cfg.queue(virtqueue_idx);
let size = queue.size;
let virtqueue = VirtQueue::new(size);
queue.desc = virtqueue.descriptor_area_dma_addr();
queue.driver = virtqueue.driver_area_dma_addr();


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Tmp

SunriseOS/virtio/src/net.rs

Lines 145 to 155 in 32af349

// TODO: Tmp
pub device: VirtioDevice,
net_config: NetConfiguration,
common_features: Features,
}
impl VirtioNet {
pub fn new(mut device: VirtioDevice) -> VirtioNet {
let net_config = NetConfiguration {
config: device.acquire_device_cfg()
};


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Is it OK to assume device is ack'd in VirtioNet::init?

SunriseOS/virtio/src/net.rs

Lines 163 to 173 in 32af349

// TODO: Is it OK to assume device is ack'd in VirtioNet::init?
// 3.1.1 Driver Requirements: Device Initialization
self.device.common_cfg.set_device_status(DeviceStatus::DRIVER);
// Negociate features
// Minimum features that we **should** negociate, as part of 5.1.4.2
let wanted_features = Features::MAC | Features::MTU;
// Additional features that would be nice to have
let wanted_features = Features::CSUM | wanted_features;


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

MSI-X Vector Configuration.

SunriseOS/virtio/src/net.rs

Lines 179 to 189 in 32af349

// TODO: MSI-X Vector Configuration.
// Virtqueue Configuration
// 5.1.5: Device Initialization
// Identify and initialize the receive and transmission virtqueues.
// TODO: Support VIRTIO_NET_F_MQ
info!("Setup virtqueues");
for virtqueue_idx in 0..2 {
self.device.setup_virtqueue(virtqueue_idx);
}


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Support VIRTIO_NET_F_MQ

SunriseOS/virtio/src/net.rs

Lines 184 to 194 in 32af349

// TODO: Support VIRTIO_NET_F_MQ
info!("Setup virtqueues");
for virtqueue_idx in 0..2 {
self.device.setup_virtqueue(virtqueue_idx);
}
if self.common_features.contains(Features::CTRL_VQ) {
// TODO: Setup ctrl_vq
}
info!("Push a ton of buffers");


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Setup ctrl_vq

SunriseOS/virtio/src/net.rs

Lines 191 to 201 in 32af349

// TODO: Setup ctrl_vq
}
info!("Push a ton of buffers");
// Fill the receive queues buffer: See 5.1.6.3
for queue in self.receive_queues() {
for item in 0..queue.len() {
//info!("Pushing buffer for item {}/{}", item, queue.len());
//if item == 63 {
// info!("{:#?}", queue);
//}


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Generate random mac

SunriseOS/virtio/src/net.rs

Lines 217 to 227 in 32af349

// TODO: Generate random mac
[0, 1, 2, 3, 4, 5]
};
info!("We're good to go!");
self.device.common_cfg.set_device_status(DeviceStatus::DRIVER_OK);
Ok(())
}
fn receive_queues(&mut self) -> impl Iterator<Item = &mut VirtQueue> {


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Generate random mac

SunriseOS/virtio/src/net.rs

Lines 270 to 280 in 32af349

// TODO: Generate random mac
[0, 1, 2, 3, 4, 5]
}
}
}
impl<'a> Device<'a> for VirtioNet {
type RxToken = VirtioNetRxToken;
type TxToken = VirtioNetTxToken<'a>;


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Instead of allocating a new vec, use scatter-gather IO.

SunriseOS/virtio/src/net.rs

Lines 327 to 337 in 32af349

// TODO: Instead of allocating a new vec, use scatter-gather IO.
let mut v = Vec::new();
v.resize(len + core::mem::size_of::<NetHdr>(), 0);
let res = f(&mut v[core::mem::size_of::<NetHdr>()..]);
v[0] = 0;/*NetHdrFlags::NEEDS_CSUM.bits()*/;
v[1] = 0;
LE::write_u16(&mut v[2..], 0);
LE::write_u16(&mut v[4..], 0);
LE::write_u16(&mut v[6..], 0);


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Blow up if cur_free_head == EOL marker.

// TODO: Blow up if cur_free_head == EOL marker.
let cur_free_head = self.free_head;
self.free_head = u16::from_le(self.descriptor_area[cur_free_head].next) as usize;
self.descriptor_area[cur_free_head].addr = (virt_to_phys(buf.as_mut_ptr()) as u64).to_le();
self.virt_area[cur_free_head] = buf.as_ptr() as usize;
self.descriptor_area[cur_free_head].len = (buf.len() as u32).to_le();
self.descriptor_area[cur_free_head].flags = DescriptorFlags::empty().bits().to_le();
self.descriptor_area[cur_free_head].next = 0;
core::mem::forget(buf);


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

@todo
Copy link

todo bot commented Jun 28, 2019

Blow up if cur_free_head == EOL marker.

// TODO: Blow up if cur_free_head == EOL marker.
let cur_free_head = self.free_head;
self.free_head = u16::from_le(self.descriptor_area[cur_free_head].next) as usize;
self.descriptor_area[cur_free_head].addr = (virt_to_phys(buf.as_mut_ptr()) as u64).to_le();
self.virt_area[cur_free_head] = buf.as_ptr() as usize;
self.descriptor_area[cur_free_head].len = (buf.capacity() as u32).to_le();
self.descriptor_area[cur_free_head].flags = DescriptorFlags::WRITE.bits().to_le();
self.descriptor_area[cur_free_head].next = 0;
core::mem::forget(buf);


This comment was generated by todo based on a TODO comment in 32af349 in #355. cc @roblabla.

Thog and others added 12 commits July 2, 2019 11:51
Remove the InPointer/InBuffer/OutPointer/OutBuffer types as they did not
have a reason to exist in the new object system. Instead, the pop_buffer
family of function now return a raw reference, whose lifetime is
selected by the caller. This simplifies the code a fair bit.
Share the PCI implementation across multiple drivers by moving it to
libuser.
The GetSystemTick syscall returns a monotonic up-counter representing a
frequency of 19200000 Hz. Note that none of our clocks actually run at
this frequency (HPET is likely to have a much higher frequency, while
PIT is likely to have a much, much, much lower frequency). As such, we
have to do some maths.

In order to implement GetSystemTick, the KERNEL_TIMER_INFO now contains
a get_tick function pointer. When the kernel timer gets selected, it
should provide an implementation of that function as a parameter to
set_kernel_timer_info.
Turns out, the spec we were basic our PCI implementation on previously
was probably a draft. After updating to a more correct spec, things
started working a lot better, unsurprisingly.
We now support auto-selected (smart) buffers. When the user fetches an
interface containing methods with smart-buffers, it will fetch the
Pointer Buffer Size. Depending on whether the smart buffer fits the
pointer buffer or not, it will be passed as either a Pointer or a
Buffer.

In order to implement this, a simple dispatch for Control messages was
implemented. The QueryPointerBufferSize function was implemented as
well.

The pointer buffer size is fetched and cached on interface creation.
Only interfaces actually containing smart buffers will fetch this
information, to avoid doing a bunch of useless IPC requests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant