Compare commits

...

5 Commits

Author SHA1 Message Date
Bananymous 82978da5e3 Kernel: Cleanup AML code 2025-01-17 16:20:00 +02:00
Bananymous 80ce9d546a Kernel: Don't error out on SYS_WAIT with W{CONTINUED,UNTRACED}
As I don't support stopping and continuing processes these flags are
effecively no-ops
2025-01-17 16:14:52 +02:00
Bananymous 34775633b2 Kernel: Clear DF on every interrupt handler
I was missing this and it lead to UB with my new mem* functions that
were implemented with `rep`
2025-01-17 16:11:13 +02:00
Bananymous 03b5c8e76e Kernel: Fix disk caching when `readonly` is specified 2025-01-16 16:16:38 +02:00
Bananymous 766b8cd62e LibC: Fix stdio FILE operations
Mixing read/write/ungetc was broken. This mostly fixes everything. There
might still be some problems that have to be fixed
2025-01-16 14:57:58 +02:00
8 changed files with 222 additions and 114 deletions

View File

@ -14,6 +14,7 @@ asm_syscall_handler:
pushl %edi pushl %edi
pushl %esi pushl %esi
pushl %ebp pushl %ebp
cld
# align stack # align stack
movl %esp, %ebp movl %esp, %ebp

View File

@ -27,6 +27,7 @@
isr_stub: isr_stub:
push_userspace push_userspace
load_kernel_segments load_kernel_segments
cld
movl %cr0, %eax; pushl %eax movl %cr0, %eax; pushl %eax
movl %cr2, %eax; pushl %eax movl %cr2, %eax; pushl %eax
@ -58,6 +59,7 @@ isr_stub:
irq_stub: irq_stub:
push_userspace push_userspace
load_kernel_segments load_kernel_segments
cld
movl 40(%esp), %eax # interrupt number movl 40(%esp), %eax # interrupt number
@ -79,6 +81,7 @@ irq_stub:
asm_yield_handler: asm_yield_handler:
# This can only be called from kernel, so no segment saving is needed # This can only be called from kernel, so no segment saving is needed
pushal pushal
cld
movl %esp, %eax # interrupt registers ptr movl %esp, %eax # interrupt registers ptr
leal 32(%esp), %ebx # interrupt stack ptr leal 32(%esp), %ebx # interrupt stack ptr
@ -101,6 +104,7 @@ asm_yield_handler:
asm_ipi_handler: asm_ipi_handler:
push_userspace push_userspace
load_kernel_segments load_kernel_segments
cld
movl %esp, %ebp movl %esp, %ebp
subl $15, %esp subl $15, %esp
@ -118,6 +122,7 @@ asm_ipi_handler:
asm_timer_handler: asm_timer_handler:
push_userspace push_userspace
load_kernel_segments load_kernel_segments
cld
movl %esp, %ebp movl %esp, %ebp
subl $15, %esp subl $15, %esp

View File

@ -16,6 +16,7 @@ asm_syscall_handler:
pushq %r13 pushq %r13
pushq %r14 pushq %r14
pushq %r15 pushq %r15
cld
movq %rsi, %r8 movq %rsi, %r8
movq %rdi, %r9 movq %rdi, %r9

View File

@ -36,7 +36,7 @@
isr_stub: isr_stub:
pushaq pushaq
cld
movq %cr0, %rax; pushq %rax movq %cr0, %rax; pushq %rax
movq %cr2, %rax; pushq %rax movq %cr2, %rax; pushq %rax
movq %cr3, %rax; pushq %rax movq %cr3, %rax; pushq %rax
@ -55,6 +55,7 @@ isr_stub:
irq_stub: irq_stub:
pushaq pushaq
cld
movq 120(%rsp), %rdi # irq number movq 120(%rsp), %rdi # irq number
call cpp_irq_handler call cpp_irq_handler
popaq popaq
@ -64,6 +65,7 @@ irq_stub:
.global asm_yield_handler .global asm_yield_handler
asm_yield_handler: asm_yield_handler:
pushaq pushaq
cld
leaq 120(%rsp), %rdi # interrupt stack ptr leaq 120(%rsp), %rdi # interrupt stack ptr
movq %rsp, %rsi # interrupt register ptr movq %rsp, %rsi # interrupt register ptr
call cpp_yield_handler call cpp_yield_handler
@ -73,6 +75,7 @@ asm_yield_handler:
.global asm_ipi_handler .global asm_ipi_handler
asm_ipi_handler: asm_ipi_handler:
pushaq pushaq
cld
call cpp_ipi_handler call cpp_ipi_handler
popaq popaq
iretq iretq
@ -80,6 +83,7 @@ asm_ipi_handler:
.global asm_timer_handler .global asm_timer_handler
asm_timer_handler: asm_timer_handler:
pushaq pushaq
cld
call cpp_timer_handler call cpp_timer_handler
popaq popaq
iretq iretq

View File

@ -283,16 +283,14 @@ namespace Kernel::ACPI::AML
switch (opcode) switch (opcode)
{ {
case AML::Byte::PackageOp: case AML::Byte::PackageOp:
if (context.aml_data.empty())
return BAN::Error::from_errno(ENODATA);
num_elements = context.aml_data[0]; num_elements = context.aml_data[0];
context.aml_data = context.aml_data.slice(1); context.aml_data = context.aml_data.slice(1);
break; break;
case AML::Byte::VarPackageOp: case AML::Byte::VarPackageOp:
{ num_elements = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))).as.integer.value;
auto node = TRY(parse_node(context));
node = TRY(convert_node(BAN::move(node), ConvInteger, sizeof(uint64_t)));
num_elements = node.as.integer.value;
break; break;
}
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
@ -1868,10 +1866,13 @@ namespace Kernel::ACPI::AML
ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::NotifyOp); ASSERT(static_cast<AML::Byte>(context.aml_data[0]) == AML::Byte::NotifyOp);
context.aml_data = context.aml_data.slice(1); context.aml_data = context.aml_data.slice(1);
auto object = TRY(parse_super_name(context, true)); auto [obj_path, obj_ref] = TRY(parse_super_name(context, true));
auto value = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t))); auto value = TRY(convert_node(TRY(parse_node(context)), ConvInteger, sizeof(uint64_t)));
dwarnln("TODO: handle notify({}, {})", object.elem2->node, value); if (obj_ref == nullptr)
return {};
dwarnln("TODO: handle notify({}, {})", obj_ref->node, value);
return {}; return {};
} }

View File

@ -692,9 +692,7 @@ namespace Kernel
if (options & ~(WCONTINUED | WNOHANG | WUNTRACED)) if (options & ~(WCONTINUED | WNOHANG | WUNTRACED))
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
// FIXME: support options stopped processes // FIXME: Add WCONTINUED and WUNTRACED when stopped/continued processes are added
if (options & ~(WCONTINUED | WUNTRACED))
return BAN::Error::from_errno(ENOTSUP);
const auto pid_matches = const auto pid_matches =
[&](const ChildExitStatus& child) [&](const ChildExitStatus& child)

View File

@ -270,7 +270,9 @@ namespace Kernel
{ {
if (!m_disk_cache.has_value()) if (!m_disk_cache.has_value())
return BAN::Error::from_errno(EIO); return BAN::Error::from_errno(EIO);
return m_disk_cache->write_to_cache(lba, buffer, true); for (size_t i = 0; i < sector_count; i++)
TRY(m_disk_cache->write_to_cache(lba + i, buffer.slice(i * sector_size(), sector_size()), true));
return {};
} }
if (!m_disk_cache.has_value()) if (!m_disk_cache.has_value())

View File

@ -17,22 +17,20 @@ struct FILE
{ {
int fd; int fd;
mode_t mode; mode_t mode;
int buffer_type;
bool eof; bool eof;
bool error; bool error;
int pid; int pid;
int unget_char; unsigned char inline_buffer[BUFSIZ];
unsigned char* buffer;
uint32_t buffer_rd_size; // 0 write buffer
uint32_t buffer_size;
uint32_t buffer_idx;
int buffer_type;
unsigned char inline_buffer_storage[BUFSIZ]; unsigned char unget_buffer[12];
unsigned char* write_buffer; uint32_t unget_buf_idx;
uint32_t wr_buf_size;
uint32_t wr_buf_index;
unsigned char read_buffer[BUFSIZ];
uint32_t rd_buf_size;
uint32_t rd_buf_index;
}; };
struct ScopeLock struct ScopeLock
@ -48,7 +46,7 @@ struct ScopeLock
funlockfile(m_file); funlockfile(m_file);
} }
FILE* m_file; FILE* const m_file;
}; };
static FILE s_files[FOPEN_MAX]; static FILE s_files[FOPEN_MAX];
@ -60,18 +58,31 @@ FILE* stddbg = &s_files[3];
static void init_closed_file(FILE* file) static void init_closed_file(FILE* file)
{ {
file->fd = -1; file->fd = -1;
file->mode = 0; file->mode = 0;
file->buffer_type = _IOLBF; file->eof = false;
file->eof = false; file->error = false;
file->error = false; file->pid = -1;
file->pid = -1; file->buffer = file->inline_buffer;
file->unget_char = EOF; file->buffer_size = sizeof(file->inline_buffer);
file->write_buffer = file->inline_buffer_storage; file->buffer_idx = 0;
file->wr_buf_size = BUFSIZ; file->buffer_type = _IOFBF;
file->wr_buf_index = 0; file->buffer_rd_size = 0;
file->rd_buf_size = 0; file->unget_buf_idx = 0;
file->rd_buf_index = 0; }
static int drop_read_buffer(FILE* file)
{
if (file->buffer_rd_size == 0)
return 0;
ASSERT(file->buffer_idx != 0);
if (file->buffer_idx == 1)
return 0;
if (syscall(SYS_SEEK, file->fd, file->buffer_idx - 1, SEEK_CUR) == -1)
return EOF;
file->buffer_rd_size = 0;
file->buffer_idx = 0;
return 0;
} }
void _init_stdio() void _init_stdio()
@ -79,18 +90,21 @@ void _init_stdio()
for (size_t i = 0; i < FOPEN_MAX; i++) for (size_t i = 0; i < FOPEN_MAX; i++)
init_closed_file(&s_files[i]); init_closed_file(&s_files[i]);
s_files[STDIN_FILENO].fd = STDIN_FILENO; s_files[STDIN_FILENO].fd = STDIN_FILENO;
s_files[STDIN_FILENO].mode = O_RDONLY; s_files[STDIN_FILENO].mode = O_RDONLY;
s_files[STDIN_FILENO].buffer_type = _IOLBF;
s_files[STDOUT_FILENO].fd = STDOUT_FILENO; s_files[STDOUT_FILENO].fd = STDOUT_FILENO;
s_files[STDOUT_FILENO].mode = O_WRONLY; s_files[STDOUT_FILENO].mode = O_WRONLY;
s_files[STDOUT_FILENO].buffer_type = _IOLBF;
s_files[STDERR_FILENO].fd = STDERR_FILENO; s_files[STDERR_FILENO].fd = STDERR_FILENO;
s_files[STDERR_FILENO].mode = O_WRONLY; s_files[STDERR_FILENO].mode = O_WRONLY;
s_files[STDERR_FILENO].buffer_type = _IONBF; s_files[STDERR_FILENO].buffer_type = _IONBF;
s_files[STDDBG_FILENO].fd = STDDBG_FILENO; s_files[STDDBG_FILENO].fd = STDDBG_FILENO;
s_files[STDDBG_FILENO].mode = O_WRONLY; s_files[STDDBG_FILENO].mode = O_WRONLY;
s_files[STDDBG_FILENO].buffer_type = _IOLBF;
} }
void clearerr(FILE* file) void clearerr(FILE* file)
@ -120,10 +134,12 @@ int dprintf(int fildes, const char* __restrict format, ...)
int fclose(FILE* file) int fclose(FILE* file)
{ {
ScopeLock _(file); ScopeLock _(file);
(void)fflush(file); if (fflush(file) == EOF)
int ret = (close(file->fd) == -1) ? EOF : 0; return EOF;
if (close(file->fd) == -1)
return EOF;
init_closed_file(file); init_closed_file(file);
return ret; return 0;
} }
static mode_t parse_mode_string(const char* mode_str) static mode_t parse_mode_string(const char* mode_str)
@ -162,9 +178,9 @@ FILE* fdopen(int fd, const char* mode_str)
continue; continue;
s_files[i].fd = fd; s_files[i].fd = fd;
s_files[i].mode = mode & O_ACCMODE; s_files[i].mode = mode & O_ACCMODE;
ASSERT(s_files[i].write_buffer == s_files[i].inline_buffer_storage); ASSERT(s_files[i].buffer == s_files[i].inline_buffer);
ASSERT(s_files[i].wr_buf_size == BUFSIZ); ASSERT(s_files[i].buffer_size == BUFSIZ);
ASSERT(s_files[i].rd_buf_size == 0); ASSERT(s_files[i].buffer_idx == 0);
return &s_files[i]; return &s_files[i];
} }
@ -186,27 +202,41 @@ int fflush(FILE* file)
{ {
if (file == nullptr) if (file == nullptr)
{ {
int ret = 0;
for (int i = 0; i < FOPEN_MAX; i++) for (int i = 0; i < FOPEN_MAX; i++)
if (s_files[i].fd != -1) if (s_files[i].fd != -1)
if (int ret = fflush(&s_files[i]); ret != 0) if (int err = fflush(&s_files[i]); err != 0)
return ret; ret = err;
return 0; return ret;
} }
ScopeLock _(file); ScopeLock _(file);
file->unget_char = EOF; if (file->fd == -1)
if (file->wr_buf_index == 0)
return 0;
if (syscall(SYS_WRITE, file->fd, file->write_buffer, file->wr_buf_index) < 0)
{ {
file->error = true; errno = EBADF;
return EOF; return EOF;
} }
file->wr_buf_index = 0; file->unget_buf_idx = 0;
if (file->buffer_rd_size)
return drop_read_buffer(file);
size_t written = 0;
while (written < file->buffer_idx)
{
ssize_t nwrite = write(file->fd, file->buffer + written, file->buffer_idx - written);
if (nwrite < 0)
{
file->error = true;
return EOF;
}
written += nwrite;
}
file->buffer_idx = 0;
return 0; return 0;
} }
@ -254,8 +284,11 @@ char* fgets(char* str, int size, FILE* file)
int fileno(FILE* fp) int fileno(FILE* fp)
{ {
if (fp == nullptr) if (fp->fd == -1)
return EBADF; {
errno = EBADF;
return -1;
}
return fp->fd; return fp->fd;
} }
@ -285,9 +318,8 @@ FILE* fopen(const char* pathname, const char* mode_str)
continue; continue;
s_files[i].fd = fd; s_files[i].fd = fd;
s_files[i].mode = mode & O_ACCMODE; s_files[i].mode = mode & O_ACCMODE;
ASSERT(s_files[i].write_buffer == s_files[i].inline_buffer_storage); ASSERT(s_files[i].buffer == s_files[i].inline_buffer);
ASSERT(s_files[i].wr_buf_size == BUFSIZ); ASSERT(s_files[i].buffer_size == BUFSIZ);
ASSERT(s_files[i].rd_buf_size == 0);
return &s_files[i]; return &s_files[i];
} }
@ -334,12 +366,13 @@ size_t fread(void* buffer, size_t size, size_t nitems, FILE* file)
if (target == 0) if (target == 0)
return 0; return 0;
unsigned char* ubuffer = static_cast<unsigned char*>(buffer);
while (nread < target) while (nread < target)
{ {
int ch = getc_unlocked(file); int ch = getc_unlocked(file);
if (ch == EOF) if (ch == EOF)
break; break;
static_cast<unsigned char*>(buffer)[nread++] = ch; ubuffer[nread++] = ch;
} }
return nread / size; return nread / size;
@ -395,13 +428,12 @@ int fseek(FILE* file, long offset, int whence)
int fseeko(FILE* file, off_t offset, int whence) int fseeko(FILE* file, off_t offset, int whence)
{ {
ScopeLock _(file); ScopeLock _(file);
file->unget_char = EOF; if (fflush(file) == EOF)
return -1;
long ret = syscall(SYS_SEEK, file->fd, offset, whence); long ret = syscall(SYS_SEEK, file->fd, offset, whence);
if (ret < 0) if (ret < 0)
return -1; return -1;
file->eof = false; file->eof = false;
file->rd_buf_size = 0;
file->rd_buf_index = 0;
return 0; return 0;
} }
@ -418,10 +450,12 @@ long ftell(FILE* file)
off_t ftello(FILE* file) off_t ftello(FILE* file)
{ {
ScopeLock _(file); ScopeLock _(file);
if (fflush(file) == EOF)
return -1;
long ret = syscall(SYS_TELL, file->fd); long ret = syscall(SYS_TELL, file->fd);
if (ret < 0) if (ret < 0)
return -1; return -1;
return ret - (file->unget_char != EOF) - (file->rd_buf_size - file->rd_buf_index); return ret;
} }
int ftrylockfile(FILE*) int ftrylockfile(FILE*)
@ -458,38 +492,65 @@ int getchar(void)
int getc_unlocked(FILE* file) int getc_unlocked(FILE* file)
{ {
if (file->fd == -1 || !(file->mode & O_RDONLY))
{
errno = EBADF;
return EOF;
}
if (file->eof) if (file->eof)
return EOF; return EOF;
if (file->unget_char != EOF) // read characters from ungetc
if (file->unget_buf_idx)
{ {
int ch = file->unget_char; file->unget_buf_idx--;
file->unget_char = EOF; unsigned char ch = file->unget_buffer[file->unget_buf_idx];
return (unsigned char)ch; if (fseeko(file, 1, SEEK_CUR) == -1)
return EOF;
return ch;
} }
if (file->rd_buf_index < file->rd_buf_size) // read from unbuffered file
return file->read_buffer[file->rd_buf_index++]; if (file->buffer_type == _IONBF)
file->rd_buf_size = 0;
file->rd_buf_index = 0;
ssize_t nread = read(file->fd, file->read_buffer, sizeof(file->read_buffer));
if (nread < 0)
{ {
file->error = true; unsigned char ch;
if (ssize_t nread = read(file->fd, &ch, 1); nread <= 0)
{
((nread == 0) ? file->eof : file->error) = true;
return EOF;
}
return ch;
}
// flush writable data
if (file->buffer_rd_size == 0 && file->buffer_idx)
if (fflush(file) == EOF)
return EOF;
// buffered read
if (file->buffer_idx < file->buffer_rd_size)
{
unsigned char ch = file->buffer[file->buffer_idx];
file->buffer_idx++;
return ch;
}
if (drop_read_buffer(file) == EOF)
return EOF;
// read into buffer
ssize_t nread = read(file->fd, file->buffer, file->buffer_size);
if (nread <= 0)
{
((nread == 0) ? file->eof : file->error) = true;
return EOF; return EOF;
} }
if (fseeko(file, 1 - nread, SEEK_CUR) == -1)
if (nread == 0)
{
file->eof = true;
return EOF; return EOF;
} file->buffer_rd_size = nread;
file->buffer_idx = 1;
file->rd_buf_size = nread; return file->buffer[0];
file->rd_buf_index = 1;
return file->read_buffer[0];
} }
int getchar_unlocked(void) int getchar_unlocked(void)
@ -502,11 +563,11 @@ char* gets(char* buffer)
if (stdin->eof) if (stdin->eof)
return nullptr; return nullptr;
unsigned char* ubuffer = (unsigned char*)buffer;
int first = fgetc(stdin); int first = fgetc(stdin);
if (first == EOF) if (first == EOF)
return nullptr; return nullptr;
unsigned char* ubuffer = reinterpret_cast<unsigned char*>(buffer);
*ubuffer++ = first; *ubuffer++ = first;
for (;;) for (;;)
@ -602,9 +663,8 @@ FILE* popen(const char* command, const char* mode_str)
s_files[i].fd = read ? fds[0] : fds[1]; s_files[i].fd = read ? fds[0] : fds[1];
s_files[i].mode = (unsigned)(read ? O_RDONLY : O_WRONLY); s_files[i].mode = (unsigned)(read ? O_RDONLY : O_WRONLY);
s_files[i].pid = pid; s_files[i].pid = pid;
ASSERT(s_files[i].write_buffer == s_files[i].inline_buffer_storage); ASSERT(s_files[i].buffer == s_files[i].inline_buffer);
ASSERT(s_files[i].wr_buf_size == BUFSIZ); ASSERT(s_files[i].buffer_size == BUFSIZ);
ASSERT(s_files[i].rd_buf_size == 0);
return &s_files[i]; return &s_files[i];
} }
@ -633,8 +693,29 @@ int putchar(int c)
int putc_unlocked(int c, FILE* file) int putc_unlocked(int c, FILE* file)
{ {
file->write_buffer[file->wr_buf_index++] = c; if (file->fd == -1 || !(file->mode & O_WRONLY))
if (file->buffer_type == _IONBF || (file->buffer_type == _IOLBF && c == '\n') || file->wr_buf_index >= file->wr_buf_size) {
errno = EBADF;
return EOF;
}
file->unget_buf_idx = 0;
if (file->buffer_rd_size && drop_read_buffer(file) == EOF)
return EOF;
if (file->buffer_type == _IONBF)
{
ssize_t nwrite = write(file->fd, &c, 1);
if (nwrite == -1)
file->error = true;
if (nwrite <= 0)
return EOF;
return (unsigned char)c;
}
file->buffer[file->buffer_idx] = c;
file->buffer_idx++;
if ((file->buffer_type == _IOLBF && c == '\n') || file->buffer_idx >= file->buffer_size)
if (fflush(file) == EOF) if (fflush(file) == EOF)
return EOF; return EOF;
return (unsigned char)c; return (unsigned char)c;
@ -746,15 +827,21 @@ int setvbuf(FILE* file, char* buffer, int type, size_t size)
return -1; return -1;
} }
if (buffer == nullptr) if (size == 0)
type = _IONBF;
unsigned char* ubuffer = reinterpret_cast<unsigned char*>(buffer);
if (ubuffer == nullptr)
{ {
buffer = reinterpret_cast<char*>(file->inline_buffer_storage); ubuffer = file->inline_buffer;
size = BAN::Math::min<size_t>(size, BUFSIZ); size = BAN::Math::min<size_t>(size, sizeof(file->inline_buffer));
} }
ASSERT(file->buffer_rd_size == 0);
ASSERT(file->buffer_idx == 0);
file->buffer_type = type; file->buffer_type = type;
file->wr_buf_size = size; file->buffer_size = size;
file->write_buffer = reinterpret_cast<unsigned char*>(buffer); file->buffer = ubuffer;
return 0; return 0;
} }
@ -789,8 +876,10 @@ int sscanf(const char* s, const char* format, ...)
// TODO // TODO
char* tempnam(const char*, const char*); char* tempnam(const char*, const char*);
// TODO FILE* tmpfile(void)
FILE* tmpfile(void); {
ASSERT_NOT_REACHED();
}
char* tmpnam(char* storage) char* tmpnam(char* storage)
{ {
@ -810,11 +899,23 @@ char* tmpnam(char* storage)
int ungetc_unlocked(int c, FILE* stream) int ungetc_unlocked(int c, FILE* stream)
{ {
if (c == EOF) if (stream->fd == -1)
{
errno = EBADF;
return EOF; return EOF;
if (stream->unget_char != EOF) }
if (c == EOF || stream->unget_buf_idx >= sizeof(stream->unget_buffer))
{
errno = EINVAL;
return EOF; return EOF;
stream->unget_char = c; }
if (fseeko(stream, -1, SEEK_CUR) == -1)
return EOF;
stream->unget_buffer[stream->unget_buf_idx] = c;
stream->unget_buf_idx++;
stream->eof = false; stream->eof = false;
return (unsigned char)c; return (unsigned char)c;
} }
@ -961,8 +1062,3 @@ int vsscanf(const char* s, const char* format, va_list arguments)
}, &s }, &s
); );
} }
FILE* tmpfile(void)
{
ASSERT_NOT_REACHED();
}