Commit 9cced14598a09efa2f3708386950b05a0712b8bc

Massice scheduler updates - multitasking almost works
  
177177 cout.set_colour(7, 0);
178178 cout << "\n\nIllegal Exception - " << (const char *)idt::exceptionMessages[r.int_no];
179179
180 cout << endl << endl << "Instruction pointer: ";
181 textmode::puthex(r.eip);
182
180183 cout << "\n\nPlease restart your computer.";
181184
182185 // We'll just halt for now, but once we have multitasking,
199199// Handle IRQs - called from the assembly stubs
200200void irq_handler(registers_t r)
201201{
202
203202 if (r.int_no >= 40)
204203 {
205204 // Send reset signal to slave PIC
212212 if(idt::interrupt_handlers[r.int_no] != 0)
213213 {
214214 // Run the handler
215 idt::isr_t irq_handler = idt::interrupt_handlers[r.int_no];
215 idt::isr_t handler = idt::interrupt_handlers[r.int_no];
216216
217 irq_handler(r);
217 handler(r);
218218 }
219219}
  
88{
99 bool initialise();
1010
11 typedef void (*isr_t)(registers_t);
11 typedef void (*isr_t)(registers_t &);
1212
1313 void register_irq(u32int irq, isr_t handler);
1414 void register_isr(u32int irq, isr_t handler);
  
129129 idt::register_irq(1, &keyboard::callback);
130130 }
131131
132 void callback(registers_t)
132 void callback(registers_t &)
133133 {
134134 u32int scancode = inb(0x60);
135135
  
2424{
2525 void initialise();
2626
27 void callback(registers_t);
27 void callback(registers_t &);
2828}
2929
3030#endif
  
100100 idt::register_isr(14, page_fault);
101101
102102 // Enable paging!
103 switch_directory(kernel_directory);
103 switch_directory(kernel_directory, true);
104104
105105 // Now we need to initialise a heap for the kernel to use
106106 kheap = heap::create_heap(KHeapStart, KHeapStart + KHeapInitialSize, 0xCFFFF000, false, false);
208208 }
209209 }
210210
211 void switch_directory(page_directory_t * dir)
211 void switch_directory(page_directory_t * dir, bool enable)
212212 {
213213 // Set the current directory to dir
214214 current_directory = dir;
216216 // Set CR3 to the physical address of the page tables
217217 asm volatile("mov %0, %%cr3":: "r"(dir->physicalAddress));
218218
219 // Get the contents of the CR0 register
220 u32int cr0;
221 asm volatile("mov %%cr0, %0": "=r"(cr0));
219 // Check we need to enable paging
220 if(enable)
221 {
222 // Get the contents of the CR0 register
223 u32int cr0;
224 asm volatile("mov %%cr0, %0": "=r"(cr0));
222225
223 // Set the bit in the CR0 register to enable paging
224 cr0 |= 0x80000000;
226 // Set the bit in the CR0 register to enable paging
227 cr0 |= 0x80000000;
225228
226 // Enable paging!
227 asm volatile("mov %0, %%cr0":: "r"(cr0));
229 // Enable paging!
230 asm volatile("mov %0, %%cr0":: "r"(cr0));
231 }
228232 }
229233
230234 page_t * get_page(uintptr address, bool make, page_directory_t * dir)
340340 }
341341
342342 // The function to handle a page fault.
343 void page_fault(registers_t regs)
343 void page_fault(registers_t &regs)
344344 {
345 // Disable interrupts
346 disable();
347
348 cout.set_colour(4, 0);
349 cout << "\n\nSymmetry encountered a fatal error:";
350
351 cout.set_colour(7, 0);
352
345353 // The fault address is stored in the CR2 register
346354 uintptr faulting_address;
347355 asm volatile("mov %%cr2, %0" : "=r" (faulting_address));
359359 int rw = regs.err_code & 0x2; // Write operation
360360 int user = regs.err_code & 0x4; // Was in user mode?
361361 int reserved = regs.err_code & 0x8; // Overwritten CPU-reserved bits of entry?
362 //int id = regs.err_code & 0x10; // Caused by instruction fetch?
363362
364 cout << "\n\nPage Fault -";
363 cout << endl << endl << "Page Fault -";
365364
366365 if(present) { cout << " page not present -"; }
367366 if(rw) { cout << " read only -"; }
370370 cout << " at ";
371371 textmode::puthex(faulting_address);
372372
373 panic("Page Fault");
373 cout << endl << endl << "EIP: ";
374 textmode::puthex(regs.eip);
375
376 // Halt indefinetely
377 halt();
374378 }
375379}
  
3939 void initialise();
4040
4141 // Switch to a different page directory
42 void switch_directory(page_directory_t * dir);
42 void switch_directory(page_directory_t * dir, bool enable = false);
4343
4444 // Return a page which is mapped to a particular address
4545 page_t * get_page(uintptr address, bool make, page_directory_t * dir);
4949 void allocate_frame(page_t * page, bool kernel, bool writable);
5050
5151 // The exception handler function for page faults
52 void page_fault(registers_t regs);
52 void page_fault(registers_t &regs);
5353
5454 // Clone a page directory
5555 page_directory_t * clone_directory(page_directory_t * src);
  
1/*
2 * Copyright (c) 2009 Stephen Gentle
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16
17#include "common.h"
18#include "stack.h"
19#include "paging.h"
20#include "memory.h"
21
22extern paging::page_directory_t * current_directory;
23
24namespace stack
25{
26 // Move the current stack to [new_stack_start]
27 void move_stack(void * new_stack_start, size_t size, uintptr initial_esp)
28 {
29 // Retrieve the old stack and base pointers
30 uintptr old_stack_pointer;
31 uintptr old_base_pointer;
32
33 asm volatile("mov %%esp, %0" : "=r" (old_stack_pointer));
34 asm volatile("mov %%ebp, %0" : "=r" (old_base_pointer));
35
36 // Calculate offset and stack and base pointers to our new stack
37 uintptr offset = (uintptr)new_stack_start - initial_esp;
38 uintptr new_stack_pointer = old_stack_pointer + offset;
39 uintptr new_base_pointer = old_base_pointer + offset;
40
41 // Copy the stack
42 copy_stack(new_stack_start, size, initial_esp);
43
44 // Switch to the new stack
45 asm volatile("mov %0, %%esp" : : "r" (new_stack_pointer));
46 asm volatile("mov %0, %%ebp" : : "r" (new_base_pointer));
47 }
48
49 // Move the current stack to [new_stack_start]
50 void copy_stack(void * new_stack_start, size_t size, uintptr initial_esp)
51 {
52 // Allocate space for the new stack
53 for(uintptr i = (uintptr)new_stack_start; i >= ((uintptr)new_stack_start - size); i -= PageSize)
54 {
55 // The stack should be user mode and writable
56 paging::allocate_frame(paging::get_page(i, true, current_directory), false, true);
57 }
58
59 // Flush the TLB by reading and writing the directory address
60 uintptr pd_addr;
61 asm volatile("mov %%cr3, %0" : "=r" (pd_addr));
62 asm volatile("mov %0, %%cr3" : : "r" (pd_addr));
63
64 uintptr old_stack_pointer;
65 uintptr old_base_pointer;
66
67 // Retrieve the old stack and base pointers
68 asm volatile("mov %%esp, %0" : "=r" (old_stack_pointer));
69 asm volatile("mov %%ebp, %0" : "=r" (old_base_pointer));
70
71 // Calculate offset and stack and base pointers to our new stack
72 uintptr offset = (uintptr)new_stack_start - initial_esp;
73 uintptr new_stack_pointer = old_stack_pointer + offset;
74 //uintptr new_base_pointer = old_base_pointer + offset;
75
76 // Copy the old stack to our net stack location
77 memcpy((void *)new_stack_pointer, (void *)old_stack_pointer, initial_esp - old_stack_pointer);
78
79 // Recurse through all the values in the new stack
80 for(uintptr i = (uintptr)new_stack_start; i < (uintptr)new_stack_start - size; i -= 4)
81 {
82 uintptr temp = *(uintptr *)i;
83
84 // Assume that temp is a base pointer if it is in the range of the old stack, and
85 // translate it to our new stack location.
86 // This will also remap any other pointers that coincidentally fall in this range.
87 if((old_stack_pointer < temp) && (temp < initial_esp))
88 {
89 temp = temp + offset;
90 uintptr * temp2 = (uintptr *)i;
91 *temp2 = temp;
92 }
93 };
94 }
95}
  
1/*
2 * Copyright (c) 2009 Stephen Gentle
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16
17#ifndef STACK_H
18#define STACK_H
19
20#include "common.h"
21
22namespace stack
23{
24 // Copy the current stack and switch to it
25 void move_stack(void * new_stack_start, size_t size, uintptr initial_esp);
26
27 // Copy the current stack
28 void copy_stack(void * new_stack_start, size_t size, uintptr initial_esp);
29}
30
31#endif
  
1/*
2 * Copyright (c) 2008 Stephen Gentle
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*/
16
17// Platform dependant multatasking code
18
19#include "common.h"
20#include "paging.h"
21
22#include "mm/virtual_address_space.h"
23
24namespace multitasking
25{
26 // Read the value of the register esp
27 uintptr read_esp()
28 {
29 uintptr temp;
30
31 asm volatile("mov %%esp, %0" : "=r"(temp));
32
33 return temp;
34 }
35
36 // Read the value of the register ebp
37 uintptr read_ebp()
38 {
39 uintptr temp;
40
41 asm volatile("mov %%ebp, %0" : "=r"(temp));
42
43 return temp;
44 }
45
46 void switch_tasks(uintptr eip, uintptr esp, uintptr ebp, virtual_address_space * addr)
47 {
48 // Get the page directory from the virtual address space
49 uintptr page_dir_address = addr->get_page_directory()->physicalAddress;
50
51 asm volatile(" \
52 cli; \
53 mov %0, %%ecx; \
54 mov %1, %%esp; \
55 mov %2, %%ebp; \
56 mov %3, %%cr3; \
57 mov $0x12345, %%eax; \
58 sti; \
59 jmp *%%ecx"
60 : : "r"(eip), "r"(esp), "r"(ebp), "r"(page_dir_address));
61 }
62}
  
2727 size_t ticks = 0;
2828
2929 // The callback that the timer interrupt will execute
30 void callback(registers_t);
30 void callback(registers_t &r);
3131
3232 void initialise(u32int frequency)
3333 {
6262 outb(0x40, higher);
6363 }
6464
65 void callback(registers_t)
65 void callback(registers_t &r)
6666 {
6767 // Increment the tick counter
6868 ticks++;
6969
7070 // It's time to run another process
71 scheduler::schedule();
71 scheduler::schedule(r);
7272 }
7373
7474 size_t get_ticks()
  
3232
3333using namespace std;
3434
35namespace textmode
36{
37 extern u32int position;
38
39 void setpos(u32int p);
40
41 void setpos(u32int p) { position = p; }
42}
43
3544// Show messages on startup?
3645bool quiet_boot = false;
3746
7070 cout.set_colour(7, 0);
7171
7272 // Test elf executable parsing
73 elf32::test("hello");
73 //elf32::test("hello");
7474
7575 cout.set_colour(2, 0);
7676 cout << "\n\nYou can test the keyboard driver by typing here. Press ESC to shut down." << endl;
7777 cout.set_colour(7, 0);
7878
79 // Just loop while we wait for interrupts
79 // The kernel has finished initialising. All kernel code run from this point will be the result
80 // of interrupts or system calls.
8081 for(; ;)
8182 {
82
83 // This is a test for threading
84 /* textmode::setpos(0);
85 cout << "KERNEL!";
86 scheduler::sleep(1000);
87 textmode::setpos(0);
88 cout << " ";
89 scheduler::sleep(1000);*/
8390 }
8491
8592 // If we break the loop for some reason, just shutdown
8693 kernel::shutdown();
8794}
8895
96int test_thread(void *)
97{
98 for(; ;)
99 {
100 textmode::setpos(20);
101 cout << "THREAD!";
102 scheduler::sleep(500);
103 textmode::setpos(20);
104 cout << " ";
105 scheduler::sleep(500);
106 }
107}
108
89109namespace kernel
90110{
91111 void initialise(struct multiboot * ptr)
124124 }
125125
126126 // Scan the initial ramdisk and get it's address
127 u32int initrd_address = initrd::scan(ptr);
127 uintptr initrd_address = initrd::scan(ptr);
128128
129129 // Set up virtual memory management
130130 paging::initialise();
  
129129}
130130
131131
132// Atoi - Cponvert a number in a string into an
133// integer
132// Atoi - Convert a number in a string into an integer
134133u32int atoi(const char * ch, u32int base)
135134{
136135 u32int num = 0;
  
2929virtual_address_space::~virtual_address_space()
3030{
3131}
32
33void virtual_address_space::switch_to()
34{
35 paging::switch_directory(m_page_directory);
36}
  
4545 return m_page_directory;
4646 }
4747
48 // Switch to this thread's page directory
49 void switch_to();
50
4851private:
4952 // This address space's page directory
5053 paging::page_directory_t * m_page_directory;
  
2121// The current thread.
2222thread * current_thread = NULL;
2323
24thread * kernel = NULL;
25thread * other = NULL;
26#include "iostream.h"
27
2428namespace scheduler
2529{
2630 // Vectors for storing the threads and processes the scheduler will use
3434 // Keep track of process IDs
3535 size_t process_id = 0;
3636
37 void schedule()
38 {
37 void schedule(registers_t &regs)
38 {
3939 // If we haven't set up multitasking yet, just exit early
4040 if(current_thread == NULL)
4141 {
4343 }
4444
4545 // Read the esp, ebp registers
46 uintptr esp, ebp, eip;
46 uintptr esp, ebp;
47
48 esp = regs.esp;
49 ebp = regs.ebp;
4750
48 esp = multitasking::read_esp();
49 ebp = multitasking::read_ebp();
50
51 // Get the current instruction pointer.
52 eip = read_eip();
53
54 // If we just executed read_eip, then eip will contain the correct value. We may
55 // have just switched tasks though, and jumped to this address, and in that case
56 // we would have just executed switch_task. We'll set the value to 0x12345 later
57 // on so we know what is happenning now
58 if(eip == 0x12345)
59 {
60 return;
61 }
62
6351 // Save the registers
64 current_thread->set_eip(eip);
52 current_thread->set_eip(regs.eip);
6553 current_thread->set_stack_ptr(esp, ebp);
6654
6755 // TODO: Get next task in vector
56 if(current_thread == kernel)
57 {
58 current_thread = other;
59 other->set_stack_ptr(esp, ebp);
60 }
61 else
62 {
63 current_thread = kernel;
64 }
6865
66 // END TEMP
67
6968 // Switch tasks
70 multitasking::switch_tasks(eip, esp, ebp, current_thread->get_parent()->get_address_space());
69 //multitasking::switch_tasks(eip, esp, ebp, current_thread->get_parent()->get_address_space());
70 regs.eip = current_thread->get_eip();
71 regs.esp = current_thread->get_esp();
72 regs.ebp = current_thread->get_ebp();
73
74 current_thread->get_parent()->get_address_space()->switch_to();
7175 }
7276
7377 size_t add_process(process * p)
  
2020#include "common.h"
2121#include "process/process.h"
2222#include "process/thread.h"
23#include "isr.h"
2324
2425namespace scheduler
2526{
26 void schedule();
27 void schedule(registers_t &regs);
2728
2829 // Add a process to the scheduler and return its pid
2930 size_t add_process(process * p);
  
1919#include "scheduler.h"
2020#include "task.h"
2121#include "paging.h"
22#include "stack.h"
2223
2324extern uintptr initial_esp;
2425extern paging::page_directory_t * current_directory;
2526extern heap::heap * kheap;
2627extern thread * current_thread;
2728
29// TEST
30extern thread * kernel;
31extern thread * other;
32extern int test_thread(void *);
33// END TEST
34
2835namespace multitasking
2936{
3037 void move_stack(void * new_stack_start, size_t size);
4444 disable();
4545
4646 // Relocate the stack to a known location
47 move_stack((void *)0xE0000000, 0x2000);
47 stack::move_stack((void *)0xE0000000, 0x2000, initial_esp);
4848
4949 // Make a new process for the kernel
5050 process * kernel_process = new process();
5353 virtual_address_space * addr = new virtual_address_space(current_directory, kheap);
5454 kernel_process->set_address_space(addr);
5555
56 current_thread = new thread(kernel_process);
56 current_thread = kernel = new thread(kernel_process);
57 other = new thread(kernel_process, test_thread, NULL);
5758
5859 // Re-enable interrupts, starting the scheduler
5960 enable();
6061
6162 debug::startup_status(true);
6263 }
63
64 // Move the initial kernel stack that Grub leaves us with to [new_stack_start]
65 void move_stack(void * new_stack_start, size_t size)
66 {
67 // Allocate space for the new stack
68 for(uintptr i = (uintptr)new_stack_start; i >= ((uintptr)new_stack_start - size); i -= PageSize)
69 {
70 // The stack should be user mode and writable
71 paging::allocate_frame(paging::get_page(i, true, current_directory), false, true);
72 }
73
74 // Flush the TLB by reading and writing the directory address
75 uintptr pd_addr;
76 asm volatile("mov %%cr3, %0" : "=r" (pd_addr));
77 asm volatile("mov %0, %%cr3" : : "r" (pd_addr));
78
79 uintptr old_stack_pointer;
80 uintptr old_base_pointer;
81
82 // Retrieve the old stack and base pointers
83 asm volatile("mov %%esp, %0" : "=r" (old_stack_pointer));
84 asm volatile("mov %%ebp, %0" : "=r" (old_base_pointer));
85
86 // Calculate offset and stack and base pointers to our new stack
87 uintptr offset = (uintptr)new_stack_start - initial_esp;
88 uintptr new_stack_pointer = old_stack_pointer + offset;
89 uintptr new_base_pointer = old_base_pointer + offset;
90
91 // Copy the old stack to our net stack location
92 memcpy((void *)new_stack_pointer, (void *)old_stack_pointer, initial_esp - old_stack_pointer);
93
94 // Recurse through all the values in the new stack
95 for(uintptr i = (uintptr)new_stack_start; i < (uintptr)new_stack_start - size; i -= 4)
96 {
97 uintptr temp = *(uintptr *)i;
98
99 // Assume that temp is a base pointer if it is in the range of the old stack, and
100 // translate it to our new stack location.
101 // This will also remap any other pointers that coincidentally fall in this range.
102 if((old_stack_pointer < temp) && (temp < initial_esp))
103 {
104 temp = temp + offset;
105 uintptr * temp2 = (uintptr *)i;
106 *temp2 = temp;
107 }
108 };
109
110 // Switch to the new stack
111 asm volatile("mov %0, %%esp" : : "r" (new_stack_pointer));
112 asm volatile("mov %0, %%ebp" : : "r" (new_base_pointer));
113 }
114
11564}
  
2525namespace multitasking
2626{
2727 void initialise();
28
29 // Defined in platform specific task.cc
30 uintptr read_esp();
31 uintptr read_ebp();
32
33 void switch_tasks(uintptr eip, uintptr esp, uintptr ebp, virtual_address_space * addr);
3428}
3529
3630#endif
  
1717#include "process/process.h"
1818#include "process/thread.h"
1919
20#include "iostream.h"
21
2022thread::thread(process * parent)
2123 : m_parent(parent), m_eip(0), m_esp(0), m_ebp(0)
2224{
2325 parent->add_thread(this);
26}
27
28thread::thread(process * parent, ThreadStart start_function, void *)
29 : m_parent(parent), m_eip(0), m_esp(0), m_ebp(0)
30{
31 parent->add_thread(this);
32
33 m_eip = (uintptr)start_function;
34 //textmode::puthex(m_eip);
2435}
2536
2637thread::~thread()
  
5656
5757 void set_stack_ptr(uintptr esp, uintptr ebp) { m_esp = esp; m_ebp = ebp; };
5858
59 // Get this thread's registers
60 uintptr get_eip() { return m_eip; };
61 uintptr get_ebp() { return m_ebp; };
62 uintptr get_esp() { return m_esp; };
63
64
65
5966private:
6067 // This thread's parent process
6168 process * m_parent;