add reparent_threadd os hooks, In Linux host, every kernel thread created in Palacios
has to call reparent_threadd to detach itself from the user process.
to different kinds of frontend devices that can act as a stream */
struct v3_stream_ops {
+ /* called by serial device to the backend stream device */
int (*read)(char *buf, uint_t len, void *private_data);
int (*write)(char *buf, uint_t len, void *private_data);
+
+ /* called by backend device to frontend serial device */
+ int (*input)(char *buf, uint_t len, void *front_data);
+ void *front_data;
};
} while (0)
-
-
+#define V3_Reparent_Threadd() \
+ do { \
+ if((os_hooks) && (os_hooks)->reparent_threaded) { \
+ (os_hooks)->reparent_threaded(); \
+ } \
+ } while(0)
/* ** */
#define V3_ASSERT(x) \
do { \
+ extern struct v3_os_hooks * os_hooks; \
if (!(x)) { \
PrintDebug("Failed assertion in %s: %s at %s, line %d, RA=%lx\n", \
__func__, #x, __FILE__, __LINE__, \
(ulong_t) __builtin_return_address(0)); \
- while(1); \
+ while(1){ \
+ if ((os_hooks) && (os_hooks)->yield_cpu) { \
+ (os_hooks)->yield_cpu(); \
+ } \
+ } \
} \
} while(0) \
void (*interrupt_cpu)(struct v3_vm_info * vm, int logical_cpu, int vector);
void (*call_on_cpu)(int logical_cpu, void (*fn)(void * arg), void * arg);
void * (*start_thread_on_cpu)(int cpu_id, int (*fn)(void * arg), void * arg, char * thread_name);
-
+ void (*reparent_threadd)(void);
};
#ifdef __V3VEE__
-#define V3_StreamOpen(path, mode) \
+#define V3_StreamOpen(path, notify_fn, private_data, mode) \
({ \
extern struct v3_stream_hooks *stream_hooks; \
((stream_hooks) && (stream_hooks)->stream_open) ? \
- (stream_hooks)->stream_open((path), (mode)) : NULL; \
+ (stream_hooks)->stream_open((path), (notify_fn), (private_data), (mode)) : NULL; \
})
#define V3_StreamRead(stream, b, l) \
#define STREAM_OPEN_MODE_WRITE (1 << 1)
struct v3_stream_hooks {
- void *(*stream_open)(const char *path, int mode);
+ void *(*stream_open)(const char *path, void (*notify)(void *), void *private_data, int mode);
int (*stream_read)(void *stream, char *buf, int len);
int (*stream_write)(void *stream, char *buf, int len);
int (*stream_close)(void *stream);
-
};
* All rights reserved.
*
* Author: Rumou Duan <duanrumou@gmail.com>
+ * Lei Xia <lxia@northwestern.edu>
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "V3VEE_LICENSE".
struct v3_stream_ops *stream_ops;
void *backend_data;
+ struct vm_device * vm_dev;
};
struct serial_port com2;
struct serial_port com3;
struct serial_port com4;
-
-
};
return 0;
}
-/*
-static void printBuffer(struct serial_buffer * buf) {
- int i = 0;
-
- for (i = 0; i < SERIAL_BUF_LEN; i++) {
- PrintDebug(" %d ", buf->buffer[i]);
- }
-
- PrintDebug("\n the number of elements is %d \n", getNumber(buf));
-}
-*/
-
-//note: write to data port is NOT implemented and corresponding codes are commented out
static int write_data_port(struct guest_info * core, uint16_t port,
void * src, uint_t length, struct vm_device * dev) {
struct serial_state * state = (struct serial_state *)dev->private_data;
*val = com_port->dll.data;
} else {
dequeue_data(&(com_port->rx_buffer), val, com_port, dev);
- }
-
+ }
+
return length;
}
return 0;
}
+static int serial_input(char *buf, uint_t len, void *front_data){
+ struct serial_port *com_port = (struct serial_port *)front_data;
+ int i;
+
+ for(i=0; i<len; i++){
+ queue_data(&(com_port->rx_buffer), buf[i], com_port, com_port->vm_dev);
+ }
+
+ return len;
+}
+
static int serial_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
struct serial_state * state = (struct serial_state *)V3_Malloc(sizeof(struct serial_state));
char * dev_id = v3_cfg_val(cfg, "ID");
- PrintDebug("UART: init_device\n");
init_serial_port(&(state->com1));
init_serial_port(&(state->com2));
init_serial_port(&(state->com3));
state->com3.irq_number = COM3_IRQ;
state->com4.irq_number = COM4_IRQ;
-
struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, state);
-
if (v3_attach_device(vm, dev) == -1) {
PrintError("Could not attach device %s\n", dev_id);
return -1;
}
+ state->com1.vm_dev = dev;
+ state->com2.vm_dev = dev;
+ state->com3.vm_dev = dev;
+ state->com4.vm_dev = dev;
+
+ PrintDebug("Serial device attached\n");
+
v3_dev_hook_io(dev, COM1_DATA_PORT, &read_data_port, &write_data_port);
v3_dev_hook_io(dev, COM1_IRQ_ENABLE_PORT, &read_ctrl_port, &write_ctrl_port);
v3_dev_hook_io(dev, COM1_FIFO_CTRL_PORT, &read_ctrl_port, &write_ctrl_port);
v3_dev_hook_io(dev, COM4_MODEM_STATUS_PORT, &read_status_port, &write_status_port);
v3_dev_hook_io(dev, COM4_SCRATCH_PORT, &read_ctrl_port, &write_ctrl_port);
+ PrintDebug("Serial ports hooked\n");
+
return 0;
}
state->com1.backend_data = private_data;
/* bind to other ports here */
+ ops->input = serial_input;
+ ops->front_data = &(state->com1);
+
return 0;
}
#include <devices/serial.h>
struct stream_state {
- void *stream;
+ void *stream_in;
+ void *stream_out;
struct vm_device *frontend_dev;
+ struct v3_stream_ops stream_ops;
};
-
static int stream_read(char *buf, uint_t length, void *private_data)
{
struct vm_device *dev = (struct vm_device *) private_data;
struct stream_state *state = (struct stream_state *) dev->private_data;
- return V3_StreamRead(state->stream,buf,length);
+ return V3_StreamRead(state->stream_out,buf,length);
}
static int stream_write(char *buf, uint_t length, void *private_data)
struct vm_device *dev = (struct vm_device *) private_data;
struct stream_state *state = (struct stream_state *) dev->private_data;
- return V3_StreamWrite(state->stream,buf,length);
+ return V3_StreamWrite(state->stream_out,buf,length);
}
-
-static struct v3_stream_ops stream_ops = {
- .write = stream_write,
- .read = stream_read,
-};
+static void notify(void * data){
+ struct stream_state *state = (struct stream_state *)data;
+ char temp[1024];
+ int len;
+
+ len = V3_StreamRead(state->stream_in, temp, 1024);
+ state->stream_ops.input(temp, len, state->stream_ops.front_data);
+}
static struct v3_device_ops dev_ops = {
.free = NULL,
const char * frontend_tag = v3_cfg_val(frontend_cfg, "tag");
struct vm_device * frontend = v3_find_dev(vm, frontend_tag);
char * dev_id = v3_cfg_val(cfg, "ID");
- char * path = v3_cfg_val(cfg, "localname");
+ char * stream_in = v3_cfg_val(cfg, "stream_in");
+ char * stream_out = v3_cfg_val(cfg, "stream_out");
struct stream_state *state;
- /* read configuration */
+
V3_ASSERT(frontend_cfg);
V3_ASSERT(frontend_tag);
V3_ASSERT(frontend);
+ V3_ASSERT(stream_in);
+ V3_ASSERT(stream_out);
-
- /* allocate state */
state = (struct stream_state *)V3_Malloc(sizeof(struct stream_state));
V3_ASSERT(state);
state->frontend_dev = frontend;
- V3_ASSERT(path);
-
- /* The system is responsible for interpreting the localname of the stream */
- state->stream = V3_StreamOpen(path, STREAM_OPEN_MODE_READ | STREAM_OPEN_MODE_WRITE);
- if (!state->stream) {
- PrintError("Could not open localname %s\n", path);
+
+ state->stream_out = V3_StreamOpen(stream_out, NULL, NULL, STREAM_OPEN_MODE_READ | STREAM_OPEN_MODE_WRITE);
+ state->stream_in = V3_StreamOpen(stream_in, notify, state, STREAM_OPEN_MODE_READ | STREAM_OPEN_MODE_WRITE);
+ if (!state->stream_out || !state->stream_in) {
+ PrintError("Could not open stream %s %s\n", stream_in, stream_out);
V3_Free(state);
return -1;
}
-
- /* allocate device */
+
struct vm_device *dev = v3_allocate_device(dev_id, &dev_ops, state);
V3_ASSERT(dev);
- /* attach device to virtual machine */
if (v3_attach_device(vm, dev) == -1) {
PrintError("Could not attach device %s\n", dev_id);
V3_Free(state);
return -1;
}
- v3_stream_register_serial(frontend, &stream_ops, dev);
-
+ state->stream_ops.read = stream_read;
+ state->stream_ops.write = stream_write;
+
+ v3_stream_register_serial(frontend, &(state->stream_ops), dev);
+
return 0;
}
io_hook->write = write;
}
-
io_hook->priv_data = priv_data;
if (insert_io_hook(vm, io_hook)) {