Skip to content

Commit

Permalink
Added support for serial input based shell and fixed some virtio-net …
Browse files Browse the repository at this point in the history
…bugs ^_^
  • Loading branch information
Jie Zheng committed Dec 10, 2018
1 parent 82a63d1 commit 3cec8db
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -57,3 +57,4 @@ dkms.conf
*.qcow2
Zelda.drive
!runtime/libc/*
qemu.log
25 changes: 19 additions & 6 deletions application/shell/hyrule_castle.c
Expand Up @@ -9,14 +9,13 @@
#include <builtin.h>
#include <zelda.h>
#include <string.h>

int exit(int);
#include <stdlib.h>
//int exit(int);

static void
shell_sigint_handler(int signal)
{
printf("Shell exits\n");
exit(0);
printf("Shell interrupted\n");
}

static char cmd_hint[128];
Expand Down Expand Up @@ -83,6 +82,7 @@ process_shell_commands(const char * path,

int main(int argc, char ** argv)
{
int is_serial0 = 0;
char command_line_buffer[MAX_COMMAND_LINE_BUFFER_LENGTH];
char oneshot_buff[MAX_ONESHOT_BUFFER_LENGTH];
int rc = 0;
Expand All @@ -91,6 +91,8 @@ int main(int argc, char ** argv)
int left = 0;
int terminate = 0;
int sub_task;
char * tty = getenv("tty");
is_serial0 = tty && !strcmp(tty, "/dev/serial0");
assert(!signal(SIGINT, shell_sigint_handler));
pseudo_terminal_enable_master();
update_cmd_hint();
Expand Down Expand Up @@ -129,13 +131,24 @@ int main(int argc, char ** argv)
}
}
iptr_inner = strlen(oneshot_buff);
if (iptr_inner)
if (iptr_inner && !is_serial0)
write(1, oneshot_buff, iptr_inner);
if (terminate)
break;
}
write(1, "\n", 1);
if (!is_serial0)
write(1, "\n", 1);
// Got one command line, process the builtin commands first
// strip '\r' one more time, in /dev/serial0, an extra '\r' is put
// into the buffer
{
for (iptr = 0; iptr < MAX_COMMAND_LINE_BUFFER_LENGTH; iptr++) {
if (command_line_buffer[iptr] == '\r') {
command_line_buffer[iptr] = '\x0';
break;
}
}
}
sub_task =
exec_command_line(command_line_buffer, process_shell_commands);
if (sub_task > 0) {
Expand Down
1 change: 1 addition & 0 deletions application/userland_init/etc/userland.init
Expand Up @@ -4,3 +4,4 @@ tty=/dev/ptm2 cwd=/home/zelda /usr/bin/shelld
tty=/dev/ptm3 cwd=/home/zelda /usr/bin/shelld
tty=/dev/ptm4 cwd=/home/zelda /usr/bin/shelld
tty=/dev/ptm5 cwd=/home/zelda /usr/bin/shelld
tty=/dev/serial0 cwd=/home/zelda /usr/bin/shelld
2 changes: 1 addition & 1 deletion application/userland_init/userland_init.c
Expand Up @@ -63,7 +63,7 @@ main(int argc, char * argv[])
for (ptr_end = ptr + 1; *ptr_end && *ptr_end != '\n'; ptr_end++);
*ptr_end = '\0';
task_id = exec_command_line(ptr, NULL);
printf("loadding;%s as task:%d\n", ptr, task_id);
printf("loading:%s as task:%d\n", ptr, task_id);
//while(wait0(task_id));
ptr = ptr_end + 1;
}
Expand Down
18 changes: 18 additions & 0 deletions device/include/pci.h
Expand Up @@ -118,6 +118,13 @@ pci_config_write_dword(uint8_t bus,
uint8_t offset,
uint32_t data);

void
pci_config_write_word(uint8_t bus,
uint8_t device,
uint8_t function,
uint8_t offset,
uint16_t data);

static inline uint16_t
pci_device_vendor_id(struct pci_device * pdev)
{
Expand Down Expand Up @@ -281,4 +288,15 @@ pci_device_interrupt_line(struct pci_device * pdev)
pdev->function,
PCI_DEVICE_INTERRUPT_LINE_OFFSET);
}
static inline void
pci_device_enable_interrupt_line(struct pci_device * pdev)
{
uint16_t command = pci_device_command(pdev);
command |= 0x404;
pci_config_write_word(pdev->bus,
pdev->device,
pdev->function,
PCI_DEVICE_COMMAND_OFFSET,
command);
}
#endif
1 change: 1 addition & 0 deletions device/include/virtio_pci.h
Expand Up @@ -22,6 +22,7 @@
#define VIRTIO_PCI_STATUS_ACK 0x1
#define VIRTIO_PCI_STATUS_DRIVER 0x2
#define VIRTIO_PCI_STATUS_DRIVER_OK 0x4
#define VIRTIO_PCI_STATUS_FEATURE_OK 0x8
#define VIRTIO_PCI_STATUS_FAIL 0x80


Expand Down
17 changes: 16 additions & 1 deletion device/pci.c
Expand Up @@ -70,7 +70,22 @@ pci_config_write_dword(uint8_t bus,
outl(PCI_OCNFIG_ADDRESS, addr);
outl(PCI_CONFIG_DATA, data);
}

void
pci_config_write_word(uint8_t bus,
uint8_t device,
uint8_t function,
uint8_t offset,
uint16_t data)
{
uint32_t addr = 0;
addr |= bus << 16;
addr |= (device & 0x1f) << 11;
addr |= (function & 0x7) << 8;
addr |= offset & 0xfc;
addr |= 0x80000000;
outl(PCI_OCNFIG_ADDRESS, addr);
outw(PCI_CONFIG_DATA, data);
}
/*
* all are deprecated below this line
*/
Expand Down
67 changes: 64 additions & 3 deletions device/serial.c
Expand Up @@ -5,8 +5,19 @@
#include <x86/include/ioport.h>
#include <kernel/include/printk.h>
#include <filesystem/include/devfs.h>
#include <x86/include/interrupt.h>
#include <lib/include/ring.h>
#include <kernel/include/task.h>
#include <kernel/include/wait_queue.h>

#define COM1_PORT 0x3f8
#define COM1_INTERRUPT_VECTOR_NUMBER 36
#define COM1_PORT 0x3f8
#define DEFAULT_SERIAL_RING_BUFFER_SIZE 64

static struct wait_queue_head wq_head;
static uint8_t local_buff_blob[
sizeof(struct ring) + DEFAULT_SERIAL_RING_BUFFER_SIZE + 1];
static struct ring * serial_local_buff = (struct ring *)local_buff_blob;

int
is_transmit_empty(void)
Expand All @@ -24,7 +35,7 @@ is_transmit_empty(void)
void
serial_init(void)
{
outb(COM1_PORT + 1, 0x00);// Disable all interrupts
outb(COM1_PORT + 1, 0x01);// Disable all interrupts except `data available`
outb(COM1_PORT + 3, 0x80);// Enable DLAB (set baud rate divisor)
outb(COM1_PORT + 0, 0x03);// Set divisor to 3 (lo byte) 38400 baud
outb(COM1_PORT + 1, 0x00);// (hi byte)
Expand Down Expand Up @@ -56,22 +67,72 @@ serial0_dev_write(struct file * file, uint32_t offset, void * buffer, int size)
}
return size;
}
static int32_t
serial0_dev_read(struct file * file, uint32_t offset, void * buffer, int size)
{
int nr_read = -ERR_GENERIC;
struct wait_queue wait;
ASSERT(current);
initialize_wait_queue_entry(&wait, current);
add_wait_queue_entry(&wq_head, &wait);

while(ring_empty(serial_local_buff)) {
transit_state(current, TASK_STATE_INTERRUPTIBLE);
yield_cpu();
if (signal_pending(current)) {
nr_read = -ERR_INTERRUPTED;
goto out;
}
}
nr_read = read_ring(serial_local_buff, buffer, size);
out:
remove_wait_queue_entry(&wq_head, &wait);
return nr_read;
}
static struct file_operation serial0_dev_ops = {
.size = serial0_dev_size,
.stat = serial0_dev_stat,
.read = NULL,
.read = serial0_dev_read,
.write = serial0_dev_write,
.truncate = NULL,
.ioctl = NULL
};
static int32_t
serial_data_available(void)
{
return inb(COM1_PORT + 5) & 1;
}

static uint8_t
serial_read(void)
{
return inb(COM1_PORT);
}

static uint32_t
serial_port_interrupt_hadnler(struct x86_cpustate * cpu)
{
uint32_t esp = (uint32_t)cpu;
while(serial_data_available()) {
ring_enqueue(serial_local_buff, serial_read());
}
wake_up(&wq_head);
return esp;
}

void
serial_post_init(void)
{
struct file_system * dev_fs = get_dev_filesystem();
initialize_wait_queue_head(&wq_head);
ASSERT(register_dev_node(dev_fs,
(uint8_t *)"/serial0",
0x0,
&serial0_dev_ops,
NULL));
register_interrupt_handler(COM1_INTERRUPT_VECTOR_NUMBER,
serial_port_interrupt_hadnler,
"Serial Port Input Handler");
serial_local_buff->ring_size = DEFAULT_SERIAL_RING_BUFFER_SIZE + 1;
ring_reset(serial_local_buff);
}
2 changes: 1 addition & 1 deletion kernel/main.c
Expand Up @@ -29,7 +29,7 @@
#include <filesystem/include/devfs.h>
#include <device/include/pseudo_terminal.h>
#include <device/include/console.h>
#include <network/include/virtio.h>
#include <network/include/virtio_net.h>


static struct multiboot_info * boot_info;
Expand Down
8 changes: 8 additions & 0 deletions lib/include/types.h
Expand Up @@ -45,4 +45,12 @@ page_round_addr(uint32_t addr)
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))

#define HIGH_BYTE(word) ((uint8_t)(((word) >> 8) & 0xff))
#define LOW_BYTE(word) ((uint8_t)((word) & 0xff))
#define MAKE_WORD(high_byte, low_byte) \
((uint16_t)(((low_byte) & 0xff) | (((high_byte) << 8) & 0xff00)))

#define mfence() {__asm__ __volatile__("mfence;":::"memory");}
#define sfence() {__asm__ __volatile__("sfence;":::"memory");}
#define lfence() {__asm__ __volatile__("lfence;":::"memory");}
#endif
27 changes: 20 additions & 7 deletions network/include/virtio.h → network/include/virtio_net.h
Expand Up @@ -2,9 +2,10 @@
* Copyright (c) 2018 Jie Zheng
*/

#ifndef _VIRTIO_H
#define _VIRTIO_H
#ifndef _VIRTIO_NET_H
#define _VIRTIO_NET_H
#include <device/include/virtio_pci.h>
#include <lib/include/ring.h>

#define VIRTIO_NET_F_CSUM (1 << 0) // Device is able to check partial sum
#define VIRTIO_NET_F_GUEST_CSUM (1 << 1) // DRIVER negotiates to use CSUM
Expand All @@ -29,16 +30,19 @@

#define VIRTIO_NET_DEVICE_CONFIG_STATUS_OFFSET (VIRTIO_PCI_DEVICE_CONFIG + 6)
#define VIRTIO_NET_DEVICE_CONFIG_NR_VQ_OFFSET (VIRTIO_PCI_DEVICE_CONFIG + 8)
// I am not supporting multiple virtqueues as of now.
// I am not supporting multiple virtqueues as of now.
#define MAX_VIRTIO_NET_VQ_PAIRS 1

// these data structures below are supposed to be within the scope of
// common transport layer, I put them here due to the fact I will implement
// no other device driver than virtnet
struct virtq_desc {
uint32_t addr;
uint32_t ___unused;
uint64_t addr;
//uint32_t ___unused;
uint32_t len;
#define VIRTQ_DESC_F_NEXT 0x1
#define VIRTQ_DESC_F_WRITE 0x2
#define VIRTQ_DESC_F_INDIRECT 0x4
//WE do not descriptor chaining and indirect buffer list
uint16_t flags;
uint16_t next;
}__attribute__((packed));
Expand All @@ -56,7 +60,7 @@ struct virt_used_elem {
}__attribute__((packed));

struct virtq_used {
#define VIRTQ_AVAIL_F_NO_INTERRUPT 0x1
#define VIRTQ_USED_F_NO_NOTIFY 0x1
uint16_t flags;
uint16_t idx;
struct virt_used_elem ring[0];
Expand All @@ -73,10 +77,19 @@ struct virtio_net {
uint16_t max_vq_pairs;

struct {
// Basic information about the virtqueue
uint32_t queue_size;
uint32_t queue_vaddr;
uint32_t queue_paddr;
uint32_t nr_pages;
// helper pointer
struct virtq_desc * vq_desc;
struct virtq_avail * vq_avail;
struct virtq_used * vq_used;
// The seperal ring buffer of free descriptors.
// the ring buffer has nothing to do with virtqueue in spec, but it
// enable us to do fast lookup for free descriptors.
struct ring * free_desc_ring;
} virtqueues[MAX_VIRTIO_NET_VQ_PAIRS * 2 + 1];
};

Expand Down

0 comments on commit 3cec8db

Please sign in to comment.