summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-03-20 18:08:57 +0100
committerAnton Kling <anton@kling.gg>2024-03-20 19:08:18 +0100
commita950021011e41b7d4fd285dde278cf9b06f89574 (patch)
tree1d88d00ac2f31d8d7c47dc84a954caea68c0b5f2
parent553b43d2e563dcff74d4c86904fa3737e96d7365 (diff)
MMU: Fixed massive problem in assumption of RAM layout
This caused certain addreses which where not RAM memory to be assigned to virtual addresses incorrectly. This caused a significant slowdown when running it with KVM due to constantly having to exit the VM if the OS writes to memory that is not RAM. This fix increased the performance of KVM significantly and improved TCG performance.
-rw-r--r--kernel/arch/i386/mmu.c103
-rw-r--r--kernel/drivers/pit.c12
-rw-r--r--kernel/includes/mmu.h4
-rw-r--r--kernel/init/kernel.c4
-rw-r--r--kernel/network/tcp.c9
-rw-r--r--kernel/process.s10
-rwxr-xr-xmeta/run.sh3
-rw-r--r--userland/irc/irc.c49
8 files changed, 125 insertions, 69 deletions
diff --git a/kernel/arch/i386/mmu.c b/kernel/arch/i386/mmu.c
index ad415a6..8761dd8 100644
--- a/kernel/arch/i386/mmu.c
+++ b/kernel/arch/i386/mmu.c
@@ -17,16 +17,20 @@ PageDirectory *kernel_directory;
PageDirectory real_kernel_directory;
PageDirectory *active_directory = 0;
+u32 num_allocated_frames = 0;
+
#define END_OF_MEMORY 0x8000000 * 15
-u64 num_of_frames;
-u32 *frames;
u64 available_memory_kb;
-u32 num_allocated_frames = 0;
+
+u32 num_array_frames = 1024;
+u32 tmp_array[1024];
+u32 *tmp_small_frames = tmp_array;
#define KERNEL_START 0xc0000000
extern uintptr_t data_end;
-void write_to_frame(u32 frame_address, u8 on);
+void change_frame(u32 frame, int on);
+u32 get_free_frame(void);
void *ksbrk(size_t s) {
uintptr_t rc = (uintptr_t)align_page((void *)data_end);
@@ -37,7 +41,6 @@ void *ksbrk(size_t s) {
// If there is no active pagedirectory we
// just assume that the memory is
// already mapped.
- get_fast_insecure_random((void *)rc, data_end - rc);
return (void *)rc;
}
// Determine whether we are approaching a unallocated table
@@ -59,7 +62,6 @@ void *ksbrk(size_t s) {
mmu_allocate_shared_kernel_region((void *)rc, (data_end - (uintptr_t)rc));
assert(((uintptr_t)rc % PAGE_SIZE) == 0);
- get_fast_insecure_random((void *)rc, data_end - rc);
return (void *)rc;
}
@@ -132,20 +134,18 @@ void *align_page(void *a) {
}
u32 first_free_frame(void) {
- for (u32 i = 1; i < INDEX_FROM_BIT(num_of_frames); i++) {
- if (frames[i] == 0xFFFFFFFF) {
+ u32 i = 1;
+ for (; i < INDEX_FROM_BIT(num_array_frames * 32); i++) {
+ if (tmp_small_frames[i] == 0xFFFFFFFF) {
continue;
}
for (u32 c = 0; c < 32; c++) {
- if (!(frames[i] & ((u32)1 << c))) {
+ if (!(tmp_small_frames[i] & ((u32)1 << c))) {
return i * 32 + c;
}
}
}
-
- kprintf("ERROR Num frames: %x\n", mmu_get_number_of_allocated_frames());
- klog("No free frames, uh oh.", LOG_ERROR);
assert(0);
return 0;
}
@@ -154,11 +154,13 @@ void write_to_frame(u32 frame_address, u8 on) {
u32 frame = frame_address / 0x1000;
if (on) {
num_allocated_frames++;
- frames[INDEX_FROM_BIT(frame)] |= ((u32)0x1 << OFFSET_FROM_BIT(frame));
+ tmp_small_frames[INDEX_FROM_BIT(frame)] |=
+ ((u32)0x1 << OFFSET_FROM_BIT(frame));
return;
}
num_allocated_frames--;
- frames[INDEX_FROM_BIT(frame)] &= ~((u32)0x1 << OFFSET_FROM_BIT(frame));
+ tmp_small_frames[INDEX_FROM_BIT(frame)] &=
+ ~((u32)0x1 << OFFSET_FROM_BIT(frame));
}
PageDirectory *get_active_pagedirectory(void) {
@@ -441,7 +443,6 @@ void mmu_map_physical(void *dst, PageDirectory *d, void *physical,
p->frame = (uintptr_t)physical / PAGE_SIZE;
write_to_frame((uintptr_t)physical, 1);
}
- flush_tlb();
}
struct PhysVirtMap {
@@ -591,12 +592,33 @@ void create_table(int table_index) {
kernel_directory->physical_tables[table_index] = (u32)physical | 0x3;
}
-void paging_init(u64 memsize) {
+void paging_init(u64 memsize, multiboot_info_t *mb) {
u32 *cr3 = (void *)get_cr3();
u32 *virtual = (u32 *)((u32)cr3 + 0xC0000000);
- frames = ksbrk(1024 * sizeof(u32));
- memset(frames, 0, 1024 * sizeof(u32));
- num_of_frames = 1024 * 32;
+
+ u32 num_of_frames = 0;
+
+ memset(tmp_small_frames, 0xFF, num_array_frames * sizeof(u32));
+ {
+ multiboot_memory_map_t *map =
+ (multiboot_memory_map_t *)(mb->mmap_addr + 0xc0000000);
+ for (int length = 0; length < mb->mmap_length;) {
+ if (MULTIBOOT_MEMORY_AVAILABLE == map->type) {
+ num_of_frames = max(num_of_frames, map->addr + map->len);
+ for (size_t i = 0; i < map->len; i += 0x20000) {
+ u32 frame = (map->addr + i) / 0x1000;
+ if (frame < (num_array_frames * 32)) {
+ tmp_small_frames[INDEX_FROM_BIT(frame)] = 0;
+ }
+ }
+ }
+ u32 delta = (uintptr_t)map->size + sizeof(map->size);
+ map = (multiboot_memory_map_t *)((uintptr_t)map + delta);
+ length += delta;
+ }
+ }
+ num_of_frames /= 0x1000;
+ num_of_frames /= 32;
kernel_directory = &real_kernel_directory;
kernel_directory->physical_address = (u32)cr3;
@@ -636,24 +658,29 @@ void paging_init(u64 memsize) {
switch_page_directory(clone_directory(kernel_directory));
move_stack(0xA0000000, 0x80000);
- u64 buffer_size = (memsize / 32) * sizeof(u32);
- // TODO: Very hacky solution since we have to memcpy the old allocation. This
- // places a strict requierment on how much RAM the system can have(altough it
- // is very small). Ideally the number of frames required would be dynamically
- // calculated.
- assert(buffer_size >= 1024 * sizeof(u32));
-
- // TODO Do this better
- // NOTE:
- // There are some addresses that point to devices rather than RAM.
- // Therefore we need frames for these to exist
- u64 min_buffer_required = 0xFD000 + 0x100000;
- buffer_size = max(min_buffer_required, buffer_size);
-
available_memory_kb = memsize;
- num_of_frames = available_memory_kb / 4;
- u32 *new_frames = ksbrk(buffer_size);
- memset(new_frames, 0, buffer_size);
- memcpy(new_frames, frames, 1024 * sizeof(u32));
- frames = new_frames;
+
+ void *new = kmalloc(num_of_frames * sizeof(u32));
+ memset(new, 0xFF, num_of_frames * sizeof(u32));
+ memcpy(new, tmp_small_frames, num_array_frames * sizeof(u32));
+ tmp_small_frames = new;
+ {
+ multiboot_memory_map_t *map =
+ (multiboot_memory_map_t *)(mb->mmap_addr + 0xc0000000);
+ for (int length = 0; length < mb->mmap_length;) {
+ if (MULTIBOOT_MEMORY_AVAILABLE == map->type) {
+ for (size_t i = 0; i < map->len - 0x1000; i += 0x20000) {
+ u32 frame = (map->addr + i) / 0x1000;
+ if (frame > (num_array_frames * 32)) {
+ assert(INDEX_FROM_BIT(frame) <= num_of_frames);
+ tmp_small_frames[INDEX_FROM_BIT(frame)] = 0;
+ }
+ }
+ }
+ u32 delta = (uintptr_t)map->size + sizeof(map->size);
+ map = (multiboot_memory_map_t *)((uintptr_t)map + delta);
+ length += delta;
+ }
+ }
+ num_array_frames = num_of_frames;
}
diff --git a/kernel/drivers/pit.c b/kernel/drivers/pit.c
index 30fd3ed..41c0d2a 100644
--- a/kernel/drivers/pit.c
+++ b/kernel/drivers/pit.c
@@ -44,16 +44,14 @@ void set_pit_count(u16 _hertz) {
}
void int_clock(reg_t *regs) {
- EOI(0x20);
- pit_counter++;
- if (pit_counter * 1000 >= hertz) {
- pit_counter = 0;
- clock_num_ms_ticks += 1000 / hertz;
- }
+ clock_num_ms_ticks++;
switch_counter++;
- if (switch_counter * 500 >= hertz) {
+ if (switch_counter >= hertz) {
+ EOI(0x20);
switch_counter = 0;
switch_task();
+ } else {
+ EOI(0x20);
}
}
diff --git a/kernel/includes/mmu.h b/kernel/includes/mmu.h
index 68fd134..1a3f7c9 100644
--- a/kernel/includes/mmu.h
+++ b/kernel/includes/mmu.h
@@ -1,6 +1,7 @@
#ifndef PAGING_H
#define PAGING_H
#include "kmalloc.h"
+#include <multiboot.h>
#include <typedefs.h>
typedef u8 mmu_flags;
@@ -49,7 +50,7 @@ void *mmu_is_valid_userpointer(const void *ptr, size_t s);
void *mmu_is_valid_user_c_string(const char *ptr, size_t *size);
void flush_tlb(void);
-void paging_init(u64 memsize);
+void paging_init(u64 memsize, multiboot_info_t *mb);
PageDirectory *get_active_pagedirectory(void);
void move_stack(u32 new_stack_address, u32 size);
void switch_page_directory(PageDirectory *directory);
@@ -58,6 +59,7 @@ PageDirectory *clone_directory(PageDirectory *original);
void *virtual_to_physical(void *address, PageDirectory *directory);
void *ksbrk(size_t s);
void *ksbrk_physical(size_t s, void **physical);
+void write_to_frame(u32 frame_address, u8 on);
Page *get_page(void *ptr, PageDirectory *directory, int create_new_page,
int set_user);
diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c
index ef7cdae..180aaa8 100644
--- a/kernel/init/kernel.c
+++ b/kernel/init/kernel.c
@@ -43,7 +43,6 @@ uintptr_t data_end;
void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr,
u32 inital_stack) {
- (void)kernel_end;
data_end = 0xc0400000;
inital_esp = inital_stack;
@@ -55,7 +54,8 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr,
u32 mem_kb = mb->mem_lower;
u32 mem_mb = (mb->mem_upper - 1000) / 1000;
u64 memsize_kb = mem_mb * 1000 + mem_kb;
- paging_init(memsize_kb);
+
+ paging_init(memsize_kb, mb);
klog("Paging Initalized", LOG_SUCCESS);
mb = mmu_map_frames((multiboot_info_t *)addr, sizeof(multiboot_info_t));
diff --git a/kernel/network/tcp.c b/kernel/network/tcp.c
index b929005..dd6e6a8 100644
--- a/kernel/network/tcp.c
+++ b/kernel/network/tcp.c
@@ -162,12 +162,11 @@ void send_tcp_packet(struct TcpConnection *con, const u8 *payload,
void handle_tcp(ipv4_t src_ip, const u8 *payload, u32 payload_length) {
const struct TCP_HEADER *header = (const struct TCP_HEADER *)payload;
(void)header;
- u16 n_src_port = *(u16 *)(payload);
- u16 n_dst_port = *(u16 *)(payload + 2);
- u32 n_seq_num = *(u32 *)(payload + 4);
- u32 n_ack_num = *(u32 *)(payload + 8);
+ u16 n_src_port = header->src_port;
+ u16 n_dst_port = header->dst_port;
+ u32 n_seq_num = header->seq_num;
+ u32 n_ack_num = header->ack_num;
- // u8 flags = *(payload + 13);
u8 flags = header->flags;
u16 src_port = htons(n_src_port);
diff --git a/kernel/process.s b/kernel/process.s
index caef941..934d627 100644
--- a/kernel/process.s
+++ b/kernel/process.s
@@ -128,15 +128,13 @@ switch_to_task:
mov eax,[esi+TCB.CR3] # eax = address of page directory for next task
mov ebx,[esi+TCB.ESP0] # ebx = address for the top of the next task's kernel stack
# mov [TSS.ESP0],ebx # Adjust the ESP0 field in the TSS (used by CPU for for CPL=3 -> CPL=0 privilege level changes)
-# mov ecx,cr3 # ecx = previous task's virtual address space
+ mov ecx,cr3 # ecx = previous task's virtual address space
-# FIXME: This branch gets a from the assembler, something about "relaxed branches".
-# this branch would probably not be used anyway but should be checked on later anyway.
-# cmp eax,ecx # Does the virtual address space need to being changed?
+ cmp eax,ecx # Does the virtual address space need to being changed?
-# je .doneVAS # no, virtual address space is the same, so don't reload it and cause TLB flushes
+ je .doneVAS # no, virtual address space is the same, so don't reload it and cause TLB flushes
mov cr3,eax # yes, load the next task's virtual address space
-#.doneVAS:
+.doneVAS:
pop ebp
pop edi
diff --git a/meta/run.sh b/meta/run.sh
index 01ec924..44fc40c 100755
--- a/meta/run.sh
+++ b/meta/run.sh
@@ -3,7 +3,8 @@ scriptdir="$(dirname "$0")"
cd "$scriptdir"
cd ..
#qemu-system-i386 -netdev user,id=n0,hostfwd=tcp:127.0.0.1:6001-:6000 -device rtl8139,netdev=n0 -object filter-dump,id=id,netdev=n0,file=./logs/netout -d int -no-reboot -no-shutdown -chardev stdio,id=char0,logfile=./logs/serial.log,signal=off -serial chardev:char0 -drive id=disk,file=./meta/ext2.img,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -m 512M -cdrom ./kernel/myos.iso -s
-qemu-system-i386 -d int -netdev user,id=n0,hostfwd=tcp:127.0.0.1:6001-:6000 -device rtl8139,netdev=n0 -object filter-dump,id=id,netdev=n0,file=./logs/netout -no-reboot -no-shutdown -chardev stdio,id=char0,logfile=./logs/serial.log,signal=off -serial chardev:char0 -drive id=disk,file=./meta/ext2.img,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -m 512M -cdrom ./kernel/myos.iso -s
+#qemu-system-i386 -d int -netdev user,id=n0,hostfwd=tcp:127.0.0.1:6001-:6000 -device rtl8139,netdev=n0 -object filter-dump,id=id,netdev=n0,file=./logs/netout -no-reboot -no-shutdown -chardev stdio,id=char0,logfile=./logs/serial.log,signal=off -serial chardev:char0 -drive id=disk,file=./meta/ext2.img,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -m 512M -cdrom ./kernel/myos.iso -s
+qemu-system-i386 -d int -netdev user,id=n0,hostfwd=tcp:127.0.0.1:6001-:6000 -device rtl8139,netdev=n0 -object filter-dump,id=id,netdev=n0,file=./logs/netout -no-reboot -no-shutdown -chardev stdio,id=char0,logfile=./logs/serial.log,signal=off -serial chardev:char0 -drive id=disk,file=./meta/ext2.img,if=none -device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -m 1G -cdrom ./kernel/myos.iso -s
# Sync the sysroot
cd ./meta/
mkdir ./mount
diff --git a/userland/irc/irc.c b/userland/irc/irc.c
index b69e1dd..297c332 100644
--- a/userland/irc/irc.c
+++ b/userland/irc/irc.c
@@ -129,20 +129,26 @@ void msg_sv_println(struct sv s) {
}
void msg_sv_print(struct sv s) {
+ char buffer[4096];
+ int buffer_pos = 0;
+ mvcursor(message_pos_x, message_pos_y);
for (size_t i = 0; i < s.length; i++) {
- mvcursor(message_pos_x, message_pos_y);
- if ('\n' == s.s[i]) {
- message_pos_x = 0;
- message_pos_y++;
- continue;
- }
- printf("%c", s.s[i]);
+ buffer[buffer_pos] = s.s[i];
+ buffer_pos++;
message_pos_x++;
- if (message_pos_x > TERMINAL_WIDTH) {
+ if ('\n' == s.s[i] || message_pos_x > TERMINAL_WIDTH) {
+ buffer[buffer_pos] = '\0';
+ printf("%s", buffer);
+ buffer_pos = 0;
message_pos_x = 0;
message_pos_y++;
+ mvcursor(message_pos_x, message_pos_y);
}
}
+ if (0 != buffer_pos) {
+ buffer[buffer_pos] = '\0';
+ printf("%s", buffer);
+ }
mvcursor(prompt_x, prompt_y);
}
@@ -154,8 +160,10 @@ void msg_sv_print(struct sv s) {
#define RPL_LUSERCLIENT C_TO_SV("251")
#define RPL_NOTOPIC C_TO_SV("331")
#define RPL_TOPIC C_TO_SV("332")
-#define ERR_NOMOTD C_TO_SV("422")
+#define RPL_NAMREPLY C_TO_SV("353")
+#define RPL_ENDOFNAMES C_TO_SV("366")
+#define ERR_NOMOTD C_TO_SV("422")
#define RPL_MOTDSTART C_TO_SV("375")
#define RPL_MOTD C_TO_SV("372")
#define RPL_ENDOFMOTD C_TO_SV("376")
@@ -234,6 +242,29 @@ void handle_msg(struct irc_server *server, struct sv msg) {
msg = sv_trim_left(msg, 1);
irc_add_message(server, channel, nick, msg);
}
+ HANDLE_CMD(RPL_NAMREPLY) {
+ struct sv intended_recipient =
+ sv_split_delim(command_parameters, &command_parameters, ' ');
+ struct sv channel_status =
+ sv_split_delim(command_parameters, &command_parameters, ' ');
+ (void)channel_status;
+ struct sv channel =
+ sv_split_delim(command_parameters, &command_parameters, ' ');
+ // Remove the ':'
+ command_parameters = sv_trim_left(command_parameters, 1);
+ if (sv_eq(intended_recipient, server_nick)) {
+ struct sb user_list_message;
+ sb_init(&user_list_message);
+ sb_append(&user_list_message, "Users on ");
+ sb_append_sv(&user_list_message, channel);
+ sb_append(&user_list_message, ": ");
+ sb_append_sv(&user_list_message, command_parameters);
+ irc_add_message(server, channel, C_TO_SV("*"), SB_TO_SV(user_list_message));
+ sb_free(&user_list_message);
+ }
+ }
+ PASSTHROUGH_CHANNEL_CMD(RPL_ENDOFNAMES)
+
PASSTHROUGH_CHANNEL_CMD(RPL_NOTOPIC)
PASSTHROUGH_CHANNEL_CMD(RPL_TOPIC)