kernel: do preparation work for copyless read/write

This commit is contained in:
Matheus
2024-09-18 21:17:37 -03:00
parent 1140244816
commit 611f13b562
12 changed files with 134 additions and 47 deletions
+11 -2
View File
@@ -1,6 +1,7 @@
#include <arch/io.h>
#include <kernel/devfs.h>
#include <logging.h>
#include <kernel/usercopy.h>
void arch_e9_putc(char c) {
#ifdef X86_64_ENABLE_E9
@@ -16,11 +17,18 @@ void arch_e9_puts(char *c) {
#endif
}
#ifdef X86_64_ENABLE_E9
static int devwrite(int minor, void *bufferp, size_t count, uintmax_t offset, int flags, size_t *wcount) {
uint8_t *buffer = bufferp;
for (uintmax_t i = 0; i < count; ++i)
outb(0xe9, buffer[i]);
for (uintmax_t i = 0; i < count; ++i) {
char c;
int error = USERCOPY_POSSIBLY_FROM_USER(&c, &buffer[i], 1);
if (error)
return error;
outb(0xe9, c);
}
*wcount = count;
return 0;
@@ -29,6 +37,7 @@ static int devwrite(int minor, void *bufferp, size_t count, uintmax_t offset, in
static devops_t devops = {
.write = devwrite
};
#endif
void arch_e9_initdev() {
#ifdef X86_64_ENABLE_E9
+4
View File
@@ -1317,6 +1317,8 @@ static int ext2_readlink(vnode_t *vnode, char **link, cred_t *cred) {
return err;
}
// this *should*, by the rules of the vnode ops, accept a user buffer. however, this will never be the case. all I/O will
// go through the page cache
static int ext2_read(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) {
if (vnode->type == V_TYPE_DIR)
return EISDIR;
@@ -1356,6 +1358,8 @@ static int ext2_read(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset
return err;
}
// this *should*, by the rules of the vnode ops, accept a user buffer. however, this will never be the case. all I/O will
// go through the page cache
int ext2_write(vnode_t *vnode, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec, cred_t *cred) {
if (vnode->type == V_TYPE_DIR)
return EISDIR;
+5
View File
@@ -130,6 +130,7 @@ static int internalpoll(vnode_t *node, polldata_t *data, int events) {
return revents;
}
// buffer can possibly be a user address
int pipefs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) {
pipenode_t *pipenode = (pipenode_t *)node;
INTERNAL_LOCK(node);
@@ -171,6 +172,8 @@ int pipefs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int
}
*readc = ringbuffer_read(&pipenode->data, buffer, size);
if (*readc == RINGBUFFER_USER_COPY_FAILED)
error = EFAULT;
// signal that there is space to write for any threads blocked on this pipe
if (RINGBUFFER_DATACOUNT(&pipenode->data) < BUFFER_SIZE - PIPE_ATOMIC_SIZE)
@@ -190,6 +193,8 @@ static int writetopipe(pipenode_t *pipenode, void *buffer, size_t size, size_t *
}
*writec = ringbuffer_write(&pipenode->data, buffer, size);
if (*writec == RINGBUFFER_USER_COPY_FAILED)
return EFAULT;
__assert(*writec);
poll_event(&pipenode->pollheader, POLLIN);
+10 -17
View File
@@ -7,15 +7,11 @@
static ringbuffer_t ringbuffer;
static pollheader_t pollheader;
static spinlock_t lock;
static mutex_t mutex;
void acpi_signaldevice(char c) {
long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC);
if (ringbuffer_write(&ringbuffer, &c, 1))
poll_event(&pollheader, POLLIN);
spinlock_releaseloweripl(&lock, ipl);
}
static int internalpoll(polldata_t *data, int events) {
@@ -43,13 +39,11 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
if (error)
return error;
MUTEX_ACQUIRE(&mutex, false);
for (;;) {
long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC);
int revents = internalpoll(&desc.data[0], POLLIN);
spinlock_releaseloweripl(&lock, ipl);
if (revents)
break;
@@ -66,13 +60,14 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
poll_leave(&desc);
}
long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC);
// this abuses a behavior of how the ringbuffer works to not need a lock for reading
// (as it would need interrupts to be off)
*readc = ringbuffer_read(&ringbuffer, buffer, size);
spinlock_releaseloweripl(&lock, ipl);
if (*readc == RINGBUFFER_USER_COPY_FAILED)
error = EFAULT;
leave:
MUTEX_RELEASE(&mutex);
poll_leave(&desc);
poll_destroydesc(&desc);
return error;
@@ -98,11 +93,9 @@ static int write(int minor, void *buffer, size_t size, uintmax_t offset, int fla
}
static int poll(int minor, polldata_t *data, int events) {
long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC);
MUTEX_ACQUIRE(&mutex, false);
int revents = internalpoll(data, events);
spinlock_releaseloweripl(&lock, ipl);
MUTEX_RELEASE(&mutex);
return revents;
}
+8 -2
View File
@@ -99,7 +99,10 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
if(size + offset > end)
size = end - offset;
memcpy(buffer, (void *)((uintptr_t)fbs[minor]->address + offset), size);
int error = USERCOPY_POSSIBLY_TO_USER(buffer, (void *)((uintptr_t)fbs[minor]->address + offset), size);
if (error)
return error;
*readc = size;
return 0;
@@ -118,7 +121,10 @@ static int write(int minor, void *buffer, size_t size, uintmax_t offset, int fla
if(size + offset > end)
size = end - offset;
memcpy((void *)((uintptr_t)fbs[minor]->address + offset), buffer, size);
int error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)fbs[minor]->address + offset), buffer, size);
if (error)
return error;
*writec = size;
return 0;
+16 -6
View File
@@ -5,6 +5,7 @@
#include <kernel/devfs.h>
#include <hashtable.h>
#include <kernel/poll.h>
#include <kernel/usercopy.h>
#define BUFFER_PACKET_CAPACITY 100
#define BUFFER_SIZE (BUFFER_PACKET_CAPACITY * sizeof(kbpacket_t))
@@ -165,25 +166,34 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
for (int i = 0; i < count; ++i) {
kbpacket_t *buff = (kbpacket_t *)((uintptr_t)buffer + i * sizeof(kbpacket_t));
bool ok = keyboard_get(kb, buff);
kbpacket_t packet;
bool ok = keyboard_get(kb, &packet);
if (ok == false) {
if (i == 0 && (flags & V_FFLAGS_NONBLOCKING) == 0) {
int err = keyboard_wait(kb, buff);
*readc += err ? 0 : sizeof(kbpacket_t);
return err;
int error = keyboard_wait(kb, &packet);
if (error)
return error;
error = USERCOPY_POSSIBLY_TO_USER(buff, &packet, sizeof(kbpacket_t));
*readc += error ? 0 : sizeof(kbpacket_t);
return error;
}
break;
}
int error = USERCOPY_POSSIBLY_TO_USER(buff, &packet, sizeof(kbpacket_t));
if (error)
return error;
*readc += sizeof(kbpacket_t);
}
return 0;
}
static int poll(int minor, polldata_t *data, int events) {
int revents = 0;
keyboard_t *kb = getkb(minor);
+5
View File
@@ -122,6 +122,11 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
}
*readc = ringbuffer_read(&mouse->packetbuffer, buffer, sizeof(mousepacket_t) * packetcount);
if (*readc == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto leave;
}
__assert(*readc);
leave:
+14
View File
@@ -365,6 +365,11 @@ static int localsock_send(socket_t *socket, sockdesc_t *sockdesc) {
}
sockdesc->donecount = ringbuffer_write(&peer->ringbuffer, sockdesc->buffer, sockdesc->count);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto leave;
}
__assert(sockdesc->donecount > 0);
error = sendctrl(socket, sockdesc->ctrl, sockdesc->ctrllen, sockdesc->donecount);
@@ -465,8 +470,17 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) {
if (flags & SOCKET_RECV_FLAGS_PEEK) {
sockdesc->donecount = ringbuffer_peek(&localsocket->ringbuffer, sockdesc->buffer, 0, recvcount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto leave;
}
} else {
sockdesc->donecount = ringbuffer_read(&localsocket->ringbuffer, sockdesc->buffer, recvcount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EPIPE;
goto leave;
}
localsocket_t *peer = pair->client == localsocket ? pair->server : pair->client;
// signal that there is space to write for any threads blocked on this socket
if (peer && sockdesc->donecount)
+20 -5
View File
@@ -1305,8 +1305,13 @@ static int tcp_send(socket_t *socket, sockdesc_t *sockdesc) {
size_t writesize = min(TCB_RINGBUFFER_SIZE - RINGBUFFER_DATACOUNT(&tcb->transmitbuffer), sockdesc->count);
__assert(writesize);
__assert(ringbuffer_write(&tcb->transmitbuffer, sockdesc->buffer, writesize) == writesize);
sockdesc->donecount = writesize;
sockdesc->donecount = ringbuffer_write(&tcb->transmitbuffer, sockdesc->buffer, writesize);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto leave;
}
__assert(sockdesc->donecount == writesize);
if (tcb->sndnext == tcb->sndunack)
error = tcp_transmitnextsegment(tcb);
@@ -1381,14 +1386,24 @@ static int tcp_recv(socket_t *socket, sockdesc_t *sockdesc) {
size_t copycount = min(RINGBUFFER_DATACOUNT(&tcb->receivebuffer), sockdesc->count);
if (flags & SOCKET_RECV_FLAGS_PEEK) {
__assert(ringbuffer_peek(&tcb->receivebuffer, sockdesc->buffer, 0, copycount) == copycount);
sockdesc->donecount = ringbuffer_peek(&tcb->receivebuffer, sockdesc->buffer, 0, copycount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto cleanup;
}
} else {
__assert(ringbuffer_read(&tcb->receivebuffer, sockdesc->buffer, copycount) == copycount);
sockdesc->donecount = ringbuffer_read(&tcb->receivebuffer, sockdesc->buffer, copycount);
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
goto cleanup;
}
tcb->rcvwindow += copycount;
// notify about the window increase
tcp_ack(tcb);
}
sockdesc->donecount = copycount;
__assert(sockdesc->donecount == copycount);
cleanup:
MUTEX_RELEASE(&tcb->mutex);
+1
View File
@@ -262,6 +262,7 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) {
bool intstate = interrupt_set(false);
spinlock_acquire(&udpsocket->ringbufferlock);
// TODO rewrite this to handle a possible sleep in the ringbuffer
size_t copycount;
dataheader_t header;
if (flags & SOCKET_RECV_FLAGS_PEEK) {
+14 -5
View File
@@ -132,10 +132,10 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
if (pty == NULL)
return ENODEV;
int e = 0;
for (;;) {
polldesc_t desc = {0};
int e = poll_initdesc(&desc, 1);
e = poll_initdesc(&desc, 1);
if (e)
return e;
@@ -146,6 +146,8 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
if (revents) {
*readc = ringbuffer_read(&pty->ringbuffer, buffer, size);
if (*readc == RINGBUFFER_USER_COPY_FAILED)
e = EFAULT;
spinlock_release(&pty->lock);
interrupt_set(intstatus);
@@ -173,7 +175,7 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
return e;
}
return 0;
return e;
}
static int poll(int minor, polldata_t *data, int events) {
@@ -215,8 +217,15 @@ static int write(int minor, void *buffer, size_t size, uintmax_t offset, int fla
char *str = buffer;
for (int i = 0; i < size; ++i)
tty_process(pty->tty, str[i]);
for (int i = 0; i < size; ++i) {
// bruh
char c;
int error = USERCOPY_POSSIBLY_FROM_USER(&c, &str[i], sizeof(char));
if (error)
return error;
tty_process(pty->tty, c);
}
*writec = size;
return 0;
+26 -10
View File
@@ -195,8 +195,13 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
if (min == 0 && time == 0) {
MUTEX_ACQUIRE(&tty->readmutex, false);
*readc = ringbuffer_read(&tty->readbuffer, buffer, size);
int error = 0;
if (*readc == RINGBUFFER_USER_COPY_FAILED)
error = EFAULT;
MUTEX_RELEASE(&tty->readmutex);
return 0;
return error;
}
// time is in 1/10 of a second
@@ -207,8 +212,6 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
size_t readcount = 0;
size_t spaceleft = size;
// TODO hangup stuff
for (;;) {
// for VMIN > 0 and VTIME > 0, the timeout is inter byte only.
size_t effectivetimeout = (min > 0 && time > 0 && spins == 0) ? 0 : timeoutus;
@@ -225,13 +228,19 @@ static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flag
MUTEX_ACQUIRE(&tty->readmutex, false);
size_t actuallyread = ringbuffer_read(&tty->readbuffer, (void *)((uintptr_t)buffer + readcount), spaceleft);
readcount += actuallyread;
spaceleft -= actuallyread;
MUTEX_RELEASE(&tty->readmutex);
// XXX is this valid?
if (spaceleft > 0 && readcount < min)
continue;
if (actuallyread == RINGBUFFER_USER_COPY_FAILED) {
error = EFAULT;
} else {
readcount += actuallyread;
spaceleft -= actuallyread;
// XXX is this valid?
if (spaceleft > 0 && readcount < min && (revents & POLLHUP) == 0)
continue;
}
poll_leave(&desc);
poll_destroydesc(&desc);
@@ -276,11 +285,18 @@ static int write(int minor, void *_buffer, size_t size, uintmax_t offset, int fl
*writec = size;
for (int i = 0; i < size; ++i) {
if (buffer[i] == '\n' && (tty->termios.c_oflag & ONLCR)) {
// bruh
char c;
int error = USERCOPY_POSSIBLY_FROM_USER(&c, &buffer[i], sizeof(char));
if (error)
return error;
if (c == '\n' && (tty->termios.c_oflag & ONLCR)) {
char cr = '\r';
tty->writetodevice(tty->deviceinternal, &cr, 1);
}
tty->writetodevice(tty->deviceinternal, &buffer[i], 1);
tty->writetodevice(tty->deviceinternal, &c, 1);
}
return 0;