A lot of hacking:

- More work on funneling console output through Console.
- init() now breaks off into a separate task ASAP.
- ..this leaves the "colonel" task as a simple hlt idle loop.
- Mask all IRQs on startup (except IRQ2 for slave passthru)
- Fix underallocation bug in Task::allocateRegion().
- Remember how many times each Task has been scheduled.

The panel and scheduling banner are disabled until I get things
working nicely in the (brave) new Console world.
This commit is contained in:
Andreas Kling 2018-10-22 11:15:16 +02:00
parent df4fdd6f1e
commit 79ffdb7205
Notes: sideshowbarker 2024-07-19 18:45:41 +09:00
13 changed files with 130 additions and 90 deletions

View File

@ -27,7 +27,30 @@ ssize_t Console::read(byte* buffer, size_t bufferSize)
void Console::putChar(char ch)
{
vga_putch(nullptr, ch);
switch (ch) {
case '\n':
m_cursorColumn = 0;
if (m_cursorRow == (m_rows - 2)) {
vga_scroll_up();
} else {
++m_cursorRow;
}
vga_set_cursor(m_cursorRow, m_cursorColumn);
return;
}
vga_putch_at(m_cursorRow, m_cursorColumn, ch);
++m_cursorColumn;
if (m_cursorColumn >= m_columns) {
if (m_cursorRow == (m_rows - 2)) {
vga_scroll_up();
} else {
++m_cursorRow;
}
m_cursorColumn = 0;
}
vga_set_cursor(m_cursorRow, m_cursorColumn);
}
ssize_t Console::write(const byte* data, size_t size)

View File

@ -33,6 +33,7 @@ public:
FileSystemTask = 4003,
MotdTask = 4004,
UserTask = 4005,
InitTask = 4006,
};
Handle(KernelTask task) : m_data((DWORD)task) { }

View File

@ -173,7 +173,7 @@ bool MemoryManager::mapRegionsForTask(Task& task)
pte.setWritable(true);
pte.setUserAllowed(!task.isRing0());
kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
//kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
}
}
return true;

View File

@ -77,14 +77,12 @@ void initialize()
IO::out8(PIC0_CMD, 0x01);
IO::out8(PIC1_CMD, 0x01 );
// Mask -- enable all interrupts on both PICs.
// Not really what I want here, but I'm unsure how to
// selectively enable secondary PIC IRQs...
IO::out8(PIC0_CMD, 0x00);
IO::out8(PIC1_CMD, 0x00);
// Mask -- start out with all IRQs disabled.
IO::out8(PIC0_CMD, 0xff);
IO::out8(PIC1_CMD, 0xff);
// HACK: Disable busmouse IRQ for now.
disable(5);
// ...except IRQ2, since that's needed for the master to let through slave interrupts.
enable(2);
kprintf("PIC(i8259): cascading mode, vectors 0x%b-0x%b\n", IRQ_VECTOR_BASE, IRQ_VECTOR_BASE + 0x08);

View File

@ -49,7 +49,7 @@ void Task::initialize()
current = nullptr;
next_pid = 0;
s_tasks = new InlineLinkedList<Task>;
s_kernelTask = new Task(0, "idle", IPC::Handle::Any, Task::Ring0);
s_kernelTask = new Task(0, "colonel", IPC::Handle::Any, Task::Ring0);
redoKernelTaskTSS();
loadTaskRegister(s_kernelTask->selector());
}
@ -96,7 +96,7 @@ Task::Region* Task::allocateRegion(size_t size, String&& name)
{
// FIXME: This needs sanity checks. What if this overlaps existing regions?
auto zone = MemoryManager::the().createZone(PAGE_SIZE);
auto zone = MemoryManager::the().createZone(size);
ASSERT(zone);
m_regions.append(make<Region>(m_nextRegion, size, move(zone), move(name)));
m_nextRegion = m_nextRegion.offset(size).offset(16384);
@ -152,6 +152,8 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
m_tss.ss = stackSegment;
m_tss.cs = codeSegment;
ASSERT((codeSegment & 3) == (stackSegment & 3));
m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get();
if (isRing0()) {
@ -160,14 +162,13 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
m_tss.eip = codeRegion->linearAddress.get();
}
kprintf("basically ready\n");
// NOTE: Each task gets 16KB of stack.
static const DWORD defaultStackSize = 16384;
if (isRing0()) {
// FIXME: This memory is leaked.
// But uh, there's also no kernel task termination, so I guess it's not technically leaked...
dword stackBottom = (dword)kmalloc(defaultStackSize);
m_stackTop = (stackBottom + defaultStackSize) & 0xffffff8;
m_tss.esp = m_stackTop;
@ -290,6 +291,13 @@ bool scheduleNewTask()
return contextSwitch(Task::kernelTask());
}
#if 0
kprintf("Scheduler choices:\n");
for (auto* task = s_tasks->head(); task; task = task->next()) {
kprintf("%p %u %s\n", task, task->pid(), task->name().characters());
}
#endif
// Check and unblock tasks whose wait conditions have been met.
for (auto* task = s_tasks->head(); task; task = task->next()) {
if (task->state() == Task::BlockedReceive && (task->ipc.msg.isValid() || task->ipc.notifies)) {
@ -320,12 +328,13 @@ bool scheduleNewTask()
auto* task = s_tasks->head();
if (task->state() == Task::Runnable || task->state() == Task::Running) {
//kprintf("switch to %s\n", task->name().characters());
//kprintf("switch to %s (%p vs %p)\n", task->name().characters(), task, current);
return contextSwitch(task);
}
if (task == prevHead) {
// Back at task_head, nothing wants to run.
kprintf("Switch to kernel task\n");
return contextSwitch(Task::kernelTask());
}
}
@ -333,6 +342,7 @@ bool scheduleNewTask()
static void drawSchedulerBanner(Task& task)
{
return;
// FIXME: We need a kernel lock to do stuff like this :(
//return;
auto c = vga_get_cursor();
@ -360,6 +370,11 @@ static bool contextSwitch(Task* t)
if (current == t)
return false;
// Some sanity checking to force a crash earlier.
auto csRPL = t->tss().cs & 3;
auto ssRPL = t->tss().ss & 3;
ASSERT(csRPL == ssRPL);
if (current) {
// If the last task hasn't blocked (still marked as running),
// mark it as runnable for the next round.
@ -396,6 +411,8 @@ static bool contextSwitch(Task* t)
flushGDT();
drawSchedulerBanner(*t);
t->didSchedule();
return true;
}
@ -481,7 +498,6 @@ FileHandle* Task::openFile(String&& path)
handle->setFD(m_fileHandles.size());
kprintf("vfs::open() worked! handle=%p, fd=%d\n", handle.ptr(), handle->fd());
m_fileHandles.append(move(handle)); // FIXME: allow non-move Vector::append
kprintf("Task::openFile(): FileHandle{%p} fd=%d\n", handle.ptr(), handle->fd());
return m_fileHandles.last().ptr();
}

View File

@ -99,6 +99,9 @@ public:
void dumpRegions();
void didSchedule() { ++m_timesScheduled; }
dword timesScheduled() const { return m_timesScheduled; }
private:
friend class MemoryManager;
@ -126,6 +129,7 @@ private:
RingLevel m_ring { Ring0 };
int m_error { 0 };
void* m_kernelStack { nullptr };
dword m_timesScheduled { 0 };
struct Region {
Region(LinearAddress, size_t, RetainPtr<Zone>&&, String&&);

View File

@ -19,36 +19,17 @@ static void console_putch(char*, char ch)
Console::the().write((byte*)&ch, 1);
}
void vga_putch(char*, char ch)
void vga_scroll_up()
{
WORD soft_cursor = vga_get_cursor();
WORD row;
memcpy(vga_mem, vga_mem + 160, 160 * 23);
memset(vga_mem + (160 * 23), 0, 160);
}
switch (ch) {
case '\n':
row = soft_cursor / 80;
if (row == 23) {
memcpy(vga_mem, vga_mem + 160, 160 * 23);
memset(vga_mem + (160 * 23), 0, 160);
soft_cursor = row * 80;
} else {
soft_cursor = (row + 1) * 80;
}
vga_set_cursor(soft_cursor);
return;
default:
vga_mem[soft_cursor * 2] = ch;
vga_mem[soft_cursor * 2 + 1] = current_attr;
++soft_cursor;
}
row = soft_cursor / 80;
if ((row >= 24 && current->handle() != IPC::Handle::PanelTask)) {
memcpy(vga_mem, vga_mem + 160, 160 * 23);
memset(vga_mem + (160 * 23), 0, 160);
soft_cursor = 23 * 80;
}
vga_set_cursor(soft_cursor);
void vga_putch_at(byte row, byte column, byte ch)
{
word cur = (row * 160) + (column * 2);
vga_mem[cur] = ch;
vga_mem[cur + 1] = current_attr;
}
template<typename PutChFunc>

View File

@ -8,7 +8,8 @@ void vga_set_attr(BYTE);
void vga_set_cursor(WORD);
void vga_set_cursor(BYTE row, BYTE column);
WORD vga_get_cursor();
void vga_putch(char*, char);
void vga_putch_at(byte row, byte column, byte ch);
void vga_scroll_up();
int kprintf(const char *fmt, ...);
int ksprintf(char* buf, const char *fmt, ...);

View File

@ -117,6 +117,15 @@ void clock_handle()
// If this IRQ occurred while in a user task, wouldn't that also push the stack ptr?
current->tss().esp = regs.esp + 12;
// FIXME: Is this really safe? What if the interrupted process didn't have SS==DS?
current->tss().ss = regs.ds;
if ((current->tss().cs & 3) != 0) {
// What do I do now?
kprintf("clk'ed across to ring0\n");
HANG;
}
// Prepare a new task to run;
if (!scheduleNewTask())
return;

View File

@ -26,9 +26,9 @@
#include <ELFLoader/ELFLoader.h>
#include "Console.h"
//#define TEST_VFS
//#define TEST_ELF_LOADER
//#define TEST_CRASHY_USER_PROCESSES
#define TEST_VFS
#define TEST_ELF_LOADER
#define TEST_CRASHY_USER_PROCESSES
#if 0
/* Keyboard LED disco task ;^) */
@ -94,16 +94,6 @@ static void user_main()
}
}
static void user_kprintf_main() NORETURN;
static void user_kprintf_main()
{
DO_SYSCALL_A1(0x4000, 0);
kprintf("This should not work!\n");
HANG;
for (;;) {
}
}
system_t system;
void banner()
@ -121,47 +111,23 @@ void banner()
kprintf("\n");
}
void init()
static void init_stage2() NORETURN;
static void init_stage2()
{
cli();
kmalloc_init();
vga_init();
auto console = make<Console>();
PIC::initialize();
gdt_init();
idt_init();
MemoryManager::initialize();
kprintf("init stage2...\n");
Keyboard::initialize();
// Anything that registers interrupts goes *after* PIC and IDT for obvious reasons.
Syscall::initialize();
PIT::initialize();
Keyboard::initialize();
Task::initialize();
VirtualFileSystem::initializeGlobals();
memset(&system, 0, sizeof(system));
WORD base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15);
WORD ext_memory = (CMOS::read(0x18) << 8) | CMOS::read(0x17);
kprintf("%u kB base memory\n", base_memory);
kprintf("%u kB extended memory\n", ext_memory);
extern void panel_main();
new Task(panel_main, "panel", IPC::Handle::PanelTask, Task::Ring0);
//new Task(led_disco, "led-disco", IPC::Handle::Any, Task::Ring0);
scheduleNewTask();
banner();
sti();
Disk::initialize();
#ifdef TEST_VFS
@ -181,7 +147,7 @@ void init()
auto dev_hd0 = IDEDiskDevice::create();
auto e2fs = Ext2FileSystem::create(dev_hd0.copyRef());
e2fs->initialize();
e2fs->initialize();
vfs->mountRoot(e2fs.copyRef());
@ -200,7 +166,6 @@ void init()
#ifdef TEST_CRASHY_USER_PROCESSES
new Task(user_main, "user", IPC::Handle::UserTask, Task::Ring3);
new Task(user_kprintf_main, "user_kprintf", IPC::Handle::UserTask, Task::Ring3);
#endif
#ifdef TEST_ELF_LOADER
@ -209,7 +174,7 @@ void init()
ASSERT(testExecutable);
auto testExecutableData = testExecutable->readEntireFile();
ASSERT(testExecutableData);
ExecSpace space;
space.loadELF(move(testExecutableData));
auto* elf_entry = space.symbolPtr("elf_entry");
@ -225,7 +190,45 @@ void init()
//new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0);
//new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
// The idle task will spend its eternity here for now.
kprintf("init stage2 is done!\n");
for (;;) {
asm("hlt");
}
}
void init()
{
cli();
kmalloc_init();
vga_init();
auto console = make<Console>();
PIC::initialize();
gdt_init();
idt_init();
MemoryManager::initialize();
PIT::initialize();
memset(&system, 0, sizeof(system));
WORD base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15);
WORD ext_memory = (CMOS::read(0x18) << 8) | CMOS::read(0x17);
kprintf("%u kB base memory\n", base_memory);
kprintf("%u kB extended memory\n", ext_memory);
Task::initialize();
auto* init2 = new Task(init_stage2, "init", IPC::Handle::InitTask, Task::Ring0);
scheduleNewTask();
sti();
// This now becomes the idle task :^)
for (;;) {
asm("hlt");
}

View File

@ -3,6 +3,6 @@
#include "VGA.h"
#define CRASH() do { asm volatile("cli;hlt"); } while(0)
#define ASSERT(x) do { if (!(x)) { vga_set_attr(0x4f); kprintf("ASSERTION FAILED: " #x "\n%s:%u in %s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); CRASH(); } } while(0)
#define ASSERT(x) do { if (!(x)) { kprintf("ASSERTION FAILED: " #x "\n%s:%u in %s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); CRASH(); } } while(0)
#define RELEASE_ASSERT(x) do { if (!(x)) CRASH(); } while(0)
#define ASSERT_NOT_REACHED() ASSERT(false)

View File

@ -16,6 +16,7 @@ panel_main()
for( ;; )
{
continue;
/* HACK: Avoid getting interrupted while painting since
* that could lead to fugly artifacts ;P */
cli();

View File

@ -27,6 +27,9 @@ VirtualFileSystem& VirtualFileSystem::the()
VirtualFileSystem::VirtualFileSystem()
{
#ifdef VFS_DEBUG
kprintf("[VFS] Constructing VFS\n");
#endif
s_the = this;
m_maxNodeCount = 16;
m_nodes = reinterpret_cast<Node*>(kmalloc(sizeof(Node) * maxNodeCount()));