add preemptive multitasking and interrupt handling
This commit is contained in:
parent
1285a8c4fe
commit
87801a1706
25 changed files with 1700 additions and 33 deletions
|
@ -75,6 +75,10 @@ Overview of all branches
|
|||
|
||||
Description of basic synchronization primitives
|
||||
|
||||
4. stage3 - Preemptive multitasking
|
||||
|
||||
Introduction into a preemptive multitasking and interrupt handling
|
||||
|
||||
Usefull Links
|
||||
-------------
|
||||
1. http://www.gnu.org/software/grub/manual/multiboot/
|
||||
|
|
163
arch/x86/include/asm/gdt.h
Normal file
163
arch/x86/include/asm/gdt.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file arch/x86/include/asm/gdt.h
|
||||
* @brief Definitions and functions related to segmentation
|
||||
* @author Stefan Lankes
|
||||
*
|
||||
* This file defines the interface for segmentation as like structures to describe segments.\n
|
||||
* There are also some other gdt-private functions in the gdt.c file defined.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_GDT_H__
|
||||
#define __ARCH_GDT_H__
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// This segment is a data segment
|
||||
#define GDT_FLAG_DATASEG 0x02
|
||||
/// This segment is a code segment
|
||||
#define GDT_FLAG_CODESEG 0x0a
|
||||
#define GDT_FLAG_TSS 0x09
|
||||
#define GDT_FLAG_TSS_BUSY 0x02
|
||||
|
||||
#define GDT_FLAG_SEGMENT 0x10
|
||||
/// Privilege level: Ring 0
|
||||
#define GDT_FLAG_RING0 0x00
|
||||
/// Privilege level: Ring 1
|
||||
#define GDT_FLAG_RING1 0x20
|
||||
/// Privilege level: Ring 2
|
||||
#define GDT_FLAG_RING2 0x40
|
||||
/// Privilege level: Ring 3
|
||||
#define GDT_FLAG_RING3 0x60
|
||||
/// Segment is present
|
||||
#define GDT_FLAG_PRESENT 0x80
|
||||
/// Segment was accessed
|
||||
#define GDT_FLAG_ACCESSED 0x01
|
||||
/**
|
||||
* @brief Granularity of segment limit
|
||||
* - set: segment limit unit is 4 KB (page size)
|
||||
* - not set: unit is bytes
|
||||
*/
|
||||
#define GDT_FLAG_4K_GRAN 0x80
|
||||
/**
|
||||
* @brief Default operand size
|
||||
* - set: 32 bit
|
||||
* - not set: 16 bit
|
||||
*/
|
||||
#define GDT_FLAG_16_BIT 0x00
|
||||
#define GDT_FLAG_32_BIT 0x40
|
||||
#define GDT_FLAG_64_BIT 0x20
|
||||
|
||||
/** @brief Defines a GDT entry
|
||||
*
|
||||
* A global descriptor table entry consists of:
|
||||
* - 32 bit base address (chunkwise embedded into this structure)
|
||||
* - 20 bit limit
|
||||
*/
|
||||
typedef struct {
|
||||
/// Lower 16 bits of limit range
|
||||
uint16_t limit_low;
|
||||
/// Lower 16 bits of base address
|
||||
uint16_t base_low;
|
||||
/// middle 8 bits of base address
|
||||
uint8_t base_middle;
|
||||
/// Access bits
|
||||
uint8_t access;
|
||||
/// Granularity bits
|
||||
uint8_t granularity;
|
||||
/// Higher 8 bits of base address
|
||||
uint8_t base_high;
|
||||
} __attribute__ ((packed)) gdt_entry_t;
|
||||
|
||||
/** @brief defines the GDT pointer structure
|
||||
*
|
||||
* This structure tells the address and size of the table.
|
||||
*/
|
||||
typedef struct {
|
||||
/// Size of the table in bytes (not the number of entries!)
|
||||
uint16_t limit;
|
||||
/// Address of the table
|
||||
size_t base;
|
||||
} __attribute__ ((packed)) gdt_ptr_t;
|
||||
|
||||
#ifdef CONFIG_LGUEST
|
||||
|
||||
// TODO TODO: Just hacked in
|
||||
#define GDT_ENTRIES 32
|
||||
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#define GDT_ENTRIES (5+MAX_TASKS)
|
||||
#else
|
||||
// a TSS descriptor is twice larger than a code/data descriptor
|
||||
#define GDT_ENTRIES (5+MAX_TASKS*2)
|
||||
#endif
|
||||
|
||||
#if GDT_ENTRIES > 8192
|
||||
#error Too many GDT entries!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/** @brief Installs the global descriptor table
|
||||
*
|
||||
* The installation involves the following steps:
|
||||
* - set up the special GDT pointer
|
||||
* - set up the entries in our GDT
|
||||
* - finally call gdt_flush() in our assembler file
|
||||
* in order to tell the processor where the new GDT is
|
||||
* - update the new segment registers
|
||||
*/
|
||||
void gdt_install(void);
|
||||
|
||||
/** @brief Set gate with chosen attributes
|
||||
*/
|
||||
void gdt_set_gate(int num, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran);
|
||||
|
||||
/** @brief Configures and returns a GDT descriptor with chosen attributes
|
||||
*
|
||||
* Just feed this function with address, limit and the flags
|
||||
* you have seen in idt.h
|
||||
*
|
||||
* @return a preconfigured gdt descriptor
|
||||
*/
|
||||
void configure_gdt_entry(gdt_entry_t *dest_entry, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
138
arch/x86/include/asm/idt.h
Normal file
138
arch/x86/include/asm/idt.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/idt.h
|
||||
* @brief Definition of IDT flags and functions to set interrupts
|
||||
*
|
||||
* This file contains define-constants for interrupt flags
|
||||
* and installer functions for interrupt gates.\n
|
||||
* See idt.c for structure definitions.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_IDT_H__
|
||||
#define __ARCH_IDT_H__
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
|
||||
/// This bit shall be set to 0 if the IDT slot is empty
|
||||
#define IDT_FLAG_PRESENT 0x80
|
||||
/// Interrupt can be called from within RING0
|
||||
#define IDT_FLAG_RING0 0x00
|
||||
/// Interrupt can be called from within RING1 and lower
|
||||
#define IDT_FLAG_RING1 0x20
|
||||
/// Interrupt can be called from within RING2 and lower
|
||||
#define IDT_FLAG_RING2 0x40
|
||||
/// Interrupt can be called from within RING3 and lower
|
||||
#define IDT_FLAG_RING3 0x60
|
||||
/// Size of gate is 16 bit
|
||||
#define IDT_FLAG_16BIT 0x00
|
||||
/// Size of gate is 32 bit
|
||||
#define IDT_FLAG_32BIT 0x08
|
||||
/// The entry describes an interrupt gate
|
||||
#define IDT_FLAG_INTTRAP 0x06
|
||||
/// The entry describes a trap gate
|
||||
#define IDT_FLAG_TRAPGATE 0x07
|
||||
/// The entry describes a task gate
|
||||
#define IDT_FLAG_TASKGATE 0x05
|
||||
|
||||
/*
|
||||
* This is not IDT-flag related. It's the segment selectors for kernel code and data.
|
||||
*/
|
||||
#define KERNEL_CODE_SELECTOR 0x08
|
||||
#define KERNEL_DATA_SELECTOR 0x10
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Defines an IDT entry
|
||||
*
|
||||
* This structure defines interrupt descriptor table entries.\n
|
||||
* They consist of the handling function's base address, some flags
|
||||
* and a segment selector.
|
||||
*/
|
||||
typedef struct {
|
||||
/// Handler function's lower 16 address bits
|
||||
uint16_t base_lo;
|
||||
/// Handler function's segment selector.
|
||||
uint16_t sel;
|
||||
/// These bits are reserved by Intel
|
||||
uint8_t always0;
|
||||
/// These 8 bits contain flags. Exact use depends on the type of interrupt gate.
|
||||
uint8_t flags;
|
||||
/// Higher 16 bits of handler function's base address
|
||||
uint16_t base_hi;
|
||||
} __attribute__ ((packed)) idt_entry_t;
|
||||
|
||||
/** @brief Defines the idt pointer structure.
|
||||
*
|
||||
* This structure keeps information about
|
||||
* base address and size of the interrupt descriptor table.
|
||||
*/
|
||||
typedef struct {
|
||||
/// Size of the IDT in bytes (not the number of entries!)
|
||||
uint16_t limit;
|
||||
/// Base address of the IDT
|
||||
size_t base;
|
||||
} __attribute__ ((packed)) idt_ptr_t;
|
||||
|
||||
/** @brief Installs IDT
|
||||
*
|
||||
* The installation involves the following steps:
|
||||
* - Set up the IDT pointer
|
||||
* - Set up int 0x80 for syscalls
|
||||
* - process idt_load()
|
||||
*/
|
||||
void idt_install(void);
|
||||
|
||||
/** @brief Set an entry in the IDT
|
||||
*
|
||||
* @param num index in the IDT
|
||||
* @param base base-address of the handler function being installed
|
||||
* @param sel Segment the IDT will use
|
||||
* @param flags Flags this entry will have
|
||||
*/
|
||||
void idt_set_gate(unsigned char num, size_t base, unsigned short sel,
|
||||
unsigned char flags);
|
||||
|
||||
/** @brief Configures and returns a IDT entry with chosen attributes
|
||||
*
|
||||
* Just feed this function with base, selector and the flags
|
||||
* you have seen in idt.h
|
||||
*
|
||||
* @return a preconfigured idt descriptor
|
||||
*/
|
||||
void configure_idt_entry(idt_entry_t *dest_entry, size_t base,
|
||||
unsigned short sel, unsigned char flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
80
arch/x86/include/asm/irq.h
Normal file
80
arch/x86/include/asm/irq.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/irq.h
|
||||
* @brief Functions related to IRQs
|
||||
*
|
||||
* This file contains functions and a pointer type related to interrupt requests.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_IRQ_H__
|
||||
#define __ARCH_IRQ_H__
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
#include <eduos/tasks_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Pointer-type to IRQ-handling functions
|
||||
*
|
||||
* Whenever you write a IRQ-handling function it has to match this signature.
|
||||
*/
|
||||
typedef void (*irq_handler_t)(struct state *);
|
||||
|
||||
/** @brief Install a custom IRQ handler for a given IRQ
|
||||
*
|
||||
* @param irq The desired irq
|
||||
* @param handler The handler to install
|
||||
*/
|
||||
int irq_install_handler(unsigned int irq, irq_handler_t handler);
|
||||
|
||||
/** @brief Clear the handler for a given IRQ
|
||||
*
|
||||
* @param irq The handler's IRQ
|
||||
*/
|
||||
int irq_uninstall_handler(unsigned int irq);
|
||||
|
||||
/** @brief Procedure to initialize IRQ
|
||||
*
|
||||
* This procedure is just a small collection of calls:
|
||||
* - idt_install();
|
||||
* - isrs_install();
|
||||
* - irq_install();
|
||||
*
|
||||
* @return Just returns 0 in any case
|
||||
*/
|
||||
int irq_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
59
arch/x86/include/asm/isrs.h
Normal file
59
arch/x86/include/asm/isrs.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/isrs.h
|
||||
* @brief Installation of interrupt service routines
|
||||
*
|
||||
* This file contains the declaration of the ISR installer procedure.\n
|
||||
* There is more interesting code related to ISRs in the isrs.c file.
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ISRS_H__
|
||||
#define __ARCH_ISRS_H__
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief ISR installer procedure
|
||||
*
|
||||
* This procedure sets the first 32 entries in the IDT
|
||||
* to the first 32 ISRs to call one general fault handler
|
||||
* which will do some dispatching and exception message logging.\n
|
||||
* The access flags are set to 0x8E (PRESENT, privilege: RING0, size: 32bit gate, type: interrupt gate).
|
||||
*/
|
||||
void isrs_install(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -37,6 +37,7 @@
|
|||
#define __ARCH_PROCESSOR_H__
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
#include <asm/gdt.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -127,6 +128,57 @@ static inline size_t lsb(size_t i)
|
|||
#define NOP8 asm volatile ("nop;nop;nop;nop;nop;nop;nop;nop")
|
||||
/// The PAUSE instruction provides a hint to the processor that the code sequence is a spin-wait loop.
|
||||
#define PAUSE asm volatile ("pause")
|
||||
/// The HALT instruction stops the processor until the next interrupt arrives
|
||||
#define HALT asm volatile ("hlt")
|
||||
|
||||
/** @brief Init several subsystems
|
||||
*
|
||||
* This function calls the initialization procedures for:
|
||||
* - GDT
|
||||
* - APIC
|
||||
* - PCI [if configured]
|
||||
*
|
||||
* @return 0 in any case
|
||||
*/
|
||||
inline static int system_init(void)
|
||||
{
|
||||
gdt_install();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Detect and read out CPU frequency
|
||||
*
|
||||
* @return The CPU frequency in MHz
|
||||
*/
|
||||
uint32_t detect_cpu_frequency(void);
|
||||
|
||||
/** @brief Read out CPU frequency if detected before
|
||||
*
|
||||
* If you did not issue the detect_cpu_frequency() function before,
|
||||
* this function will call it implicitly.
|
||||
*
|
||||
* @return The CPU frequency in MHz
|
||||
*/
|
||||
uint32_t get_cpu_frequency(void);
|
||||
|
||||
/** @brief Busywait an microseconds interval of time
|
||||
* @param usecs The time to wait in microseconds
|
||||
*/
|
||||
void udelay(uint32_t usecs);
|
||||
|
||||
/** @brief System calibration
|
||||
*
|
||||
* This procedure will detect the CPU frequency and calibrate the APIC timer.
|
||||
*
|
||||
* @return 0 in any case.
|
||||
*/
|
||||
inline static int system_calibration(void)
|
||||
{
|
||||
detect_cpu_frequency();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -71,6 +71,10 @@ typedef unsigned short wchar_t;
|
|||
|
||||
/// This defines what the stack looks like after the task context is saved.
|
||||
struct state {
|
||||
/// ds register
|
||||
uint32_t ds;
|
||||
/// es register
|
||||
uint32_t es;
|
||||
/// EDI register
|
||||
uint32_t edi;
|
||||
/// ESI register
|
||||
|
@ -88,10 +92,16 @@ struct state {
|
|||
/// EAX register
|
||||
uint32_t eax; /* pushed by 'pusha' */
|
||||
|
||||
// state of the controll register
|
||||
uint32_t eflags;
|
||||
/// state of instruction pointer
|
||||
/// Interrupt number
|
||||
uint32_t int_no;
|
||||
|
||||
// pushed by the processor automatically
|
||||
uint32_t error;
|
||||
uint32_t eip;
|
||||
uint32_t cs;
|
||||
uint32_t eflags;
|
||||
uint32_t useresp;
|
||||
uint32_t ss;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
72
arch/x86/include/asm/tss.h
Normal file
72
arch/x86/include/asm/tss.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/include/asm/tss.h
|
||||
* @brief Task state segment structure definition
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_TSS_H__
|
||||
#define __ARCH_TSS_H__
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief The tast state segment structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t backlink, __blh;
|
||||
uint32_t esp0;
|
||||
uint16_t ss0, __ss0h;
|
||||
uint32_t esp1;
|
||||
uint16_t ss1, __ss1h;
|
||||
uint32_t esp2;
|
||||
uint16_t ss2, __ss2h;
|
||||
uint32_t cr3;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t eax, ecx, edx, ebx;
|
||||
uint32_t esp, ebp, esi, edi;
|
||||
uint16_t es, __esh;
|
||||
uint16_t cs, __csh;
|
||||
uint16_t ss, __ssh;
|
||||
uint16_t ds, __dsh;
|
||||
uint16_t fs, __fsh;
|
||||
uint16_t gs, __gsh;
|
||||
uint16_t ldt, __ldth;
|
||||
uint16_t trace, bitmap;
|
||||
} __attribute__ ((packed)) tss_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
C_source := tasks.c multiboot.c vga.c
|
||||
C_source := tasks.c multiboot.c vga.c gdt.c irq.c idt.c isrs.c timer.c processor.c
|
||||
ASM_source := entry.asm string32.asm
|
||||
MODULE := arch_x86_kernel
|
||||
|
||||
|
|
|
@ -24,6 +24,13 @@
|
|||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
; This is the kernel's entry point. We could either call main here,
|
||||
; or we can use this to setup the stack or other nice stuff, like
|
||||
; perhaps setting up the GDT and segments. Please note that interrupts
|
||||
; are disabled at this point: More on interrupts later!
|
||||
|
||||
%include "config.inc"
|
||||
|
||||
[BITS 32]
|
||||
; We use a special name to map this section at the begin of our kernel
|
||||
; => Multiboot needs its magic number at the begin of the kernel
|
||||
|
@ -50,8 +57,9 @@ mboot:
|
|||
SECTION .text
|
||||
ALIGN 4
|
||||
stublet:
|
||||
; initialize stack pointer.
|
||||
mov esp, default_stack_pointer
|
||||
; initialize stack pointer
|
||||
mov esp, boot_stack
|
||||
add esp, KERNEL_STACK_SIZE-16
|
||||
; initialize cpu features
|
||||
call cpu_init
|
||||
; interpret multiboot information
|
||||
|
@ -82,34 +90,178 @@ cpu_init:
|
|||
mov cr4, eax
|
||||
ret
|
||||
|
||||
; This will set up our new segment registers. We need to do
|
||||
; something special in order to set CS. We do what is called a
|
||||
; far jump. A jump that includes a segment as well as an offset.
|
||||
; This is declared in C as 'extern void gdt_flush();'
|
||||
global gdt_flush
|
||||
extern gp
|
||||
gdt_flush:
|
||||
lgdt [gp]
|
||||
mov ax, 0x10
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
jmp 0x08:flush2
|
||||
flush2:
|
||||
ret
|
||||
|
||||
; The first 32 interrupt service routines (isr) entries correspond to exceptions.
|
||||
; Some exceptions will push an error code onto the stack which is specific to
|
||||
; the exception caused. To decrease the complexity, we handle this by pushing a
|
||||
; dummy error code of 0 onto the stack for any ISR that doesn't push an error
|
||||
; code already.
|
||||
;
|
||||
; ISRs are registered as "Interrupt Gate".
|
||||
; Therefore, the interrupt flag (IF) is already cleared.
|
||||
|
||||
; NASM macro which pushs also an pseudo error code
|
||||
%macro isrstub_pseudo_error 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte %1
|
||||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; Similar to isrstub_pseudo_error, but without pushing
|
||||
; a pseudo error code => The error code is already
|
||||
; on the stack.
|
||||
%macro isrstub 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
push byte %1
|
||||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; create isr entries, where the number after the
|
||||
; pseudo error code represents following interrupts
|
||||
; 0: Divide By Zero Exception
|
||||
; 1: Debug Exception
|
||||
; 2: Non Maskable Interrupt Exception
|
||||
; 3: Int 3 Exception
|
||||
; 4: INTO Exception
|
||||
; 5: Out of Bounds Exception
|
||||
; 6: Invalid Opcode Exception
|
||||
; 7: Coprocessor Not Available Exception
|
||||
%assign i 0
|
||||
%rep 8
|
||||
isrstub_pseudo_error i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; 8: Double Fault Exception (With Error Code!)
|
||||
isrstub 8
|
||||
|
||||
; 9: Coprocessor Segment Overrun Exception
|
||||
isrstub_pseudo_error 9
|
||||
|
||||
; 10: Bad TSS Exception (With Error Code!)
|
||||
; 11: Segment Not Present Exception (With Error Code!)
|
||||
; 12: Stack Fault Exception (With Error Code!)
|
||||
; 13: General Protection Fault Exception (With Error Code!)
|
||||
; 14: Page Fault Exception (With Error Code!)
|
||||
%assign i 10
|
||||
%rep 5
|
||||
isrstub i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; 15: Reserved Exception
|
||||
; 16: Floating Point Exception
|
||||
; 17: Alignment Check Exception
|
||||
; 18: Machine Check Exceptio
|
||||
; 19-31: Reserved
|
||||
%assign i 15
|
||||
%rep 17
|
||||
isrstub_pseudo_error i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
; NASM macro for asynchronous interrupts (no exceptions)
|
||||
%macro irqstub 1
|
||||
global irq%1
|
||||
irq%1:
|
||||
push byte 0 ; pseudo error code
|
||||
push byte 32+%1
|
||||
jmp common_stub
|
||||
%endmacro
|
||||
|
||||
; create entries for the interrupts 0 to 23
|
||||
%assign i 0
|
||||
%rep 24
|
||||
irqstub i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
||||
extern irq_handler
|
||||
extern get_current_stack
|
||||
extern finish_task_switch
|
||||
|
||||
global switch_context
|
||||
ALIGN 4
|
||||
switch_context:
|
||||
; create on the stack a pseudo interrupt
|
||||
; afterwards, we switch to the task with iret
|
||||
; we already in kernel space => no pushing of SS required
|
||||
mov eax, [esp+4] ; on the stack is already the address to store the old esp
|
||||
pushf ; push controll register
|
||||
push DWORD 0x8 ; CS
|
||||
push DWORD rollback ; EIP
|
||||
push DWORD 0x0 ; Interrupt number
|
||||
push DWORD 0x00edbabe ; Error code
|
||||
pusha ; push all general purpose registers...
|
||||
push 0x10 ; kernel data segment
|
||||
push 0x10 ; kernel data segment
|
||||
|
||||
mov [eax], esp ; store old esp
|
||||
call get_current_stack ; get new esp
|
||||
jmp common_switch
|
||||
|
||||
ALIGN 4
|
||||
rollback:
|
||||
ret
|
||||
|
||||
ALIGN 4
|
||||
common_stub:
|
||||
pusha
|
||||
push es
|
||||
push ds
|
||||
mov ax, 0x10
|
||||
mov es, ax
|
||||
mov ds, ax
|
||||
|
||||
; use the same handler for interrupts and exceptions
|
||||
push esp
|
||||
call irq_handler
|
||||
add esp, 4
|
||||
|
||||
cmp eax, 0
|
||||
je no_context_switch
|
||||
|
||||
common_switch:
|
||||
mov [eax], esp ; store old esp
|
||||
call get_current_stack ; get new esp
|
||||
xchg eax, esp
|
||||
|
||||
; set task switched flag
|
||||
mov eax, cr0
|
||||
or eax, 8
|
||||
mov cr0, eax
|
||||
|
||||
; call cleanup code
|
||||
call finish_task_switch
|
||||
|
||||
; restore context
|
||||
no_context_switch:
|
||||
pop ds
|
||||
pop es
|
||||
popa
|
||||
popf
|
||||
ret
|
||||
add esp, 8
|
||||
iret
|
||||
|
||||
; Here is the definition of our stack. Remember that a stack actually grows
|
||||
; downwards, so we declare the size of the data before declaring
|
||||
; the identifier 'default_stack_pointer'
|
||||
SECTION .data
|
||||
resb 8192 ; This reserves 8KBytes of memory here
|
||||
global default_stack_pointer
|
||||
default_stack_pointer:
|
||||
global boot_stack
|
||||
ALIGN 4096
|
||||
boot_stack:
|
||||
TIMES (KERNEL_STACK_SIZE) DB 0xcd
|
||||
|
||||
SECTION .note.GNU-stack noalloc noexec nowrite progbits
|
||||
|
|
137
arch/x86/kernel/gdt.c
Normal file
137
arch/x86/kernel/gdt.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/stdlib.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/errno.h>
|
||||
#include <eduos/processor.h>
|
||||
#include <eduos/time.h>
|
||||
#include <asm/gdt.h>
|
||||
#include <asm/tss.h>
|
||||
|
||||
gdt_ptr_t gp;
|
||||
static tss_t task_state_segment __attribute__ ((aligned (PAGE_SIZE)));
|
||||
// currently, our kernel has full access to the ioports
|
||||
static gdt_entry_t gdt[GDT_ENTRIES] = {[0 ... GDT_ENTRIES-1] = {0, 0, 0, 0, 0, 0}};
|
||||
|
||||
/*
|
||||
* This is defined in entry.asm. We use this to properly reload
|
||||
* the new segment registers
|
||||
*/
|
||||
extern void gdt_flush(void);
|
||||
|
||||
/* Setup a descriptor in the Global Descriptor Table */
|
||||
void gdt_set_gate(int num, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran)
|
||||
{
|
||||
configure_gdt_entry(&gdt[num], base, limit, access, gran);
|
||||
}
|
||||
|
||||
void configure_gdt_entry(gdt_entry_t *dest_entry, unsigned long base, unsigned long limit,
|
||||
unsigned char access, unsigned char gran)
|
||||
{
|
||||
/* Setup the descriptor base address */
|
||||
dest_entry->base_low = (base & 0xFFFF);
|
||||
dest_entry->base_middle = (base >> 16) & 0xFF;
|
||||
dest_entry->base_high = (base >> 24) & 0xFF;
|
||||
|
||||
/* Setup the descriptor limits */
|
||||
dest_entry->limit_low = (limit & 0xFFFF);
|
||||
dest_entry->granularity = ((limit >> 16) & 0x0F);
|
||||
|
||||
/* Finally, set up the granularity and access flags */
|
||||
dest_entry->granularity |= (gran & 0xF0);
|
||||
dest_entry->access = access;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will setup the special GDT
|
||||
* pointer, set up the entries in our GDT, and then
|
||||
* finally call gdt_flush() in our assembler file in order
|
||||
* to tell the processor where the new GDT is and update the
|
||||
* new segment registers
|
||||
*/
|
||||
void gdt_install(void)
|
||||
{
|
||||
unsigned long mode, limit;
|
||||
|
||||
memset(&task_state_segment, 0x00, sizeof(tss_t));
|
||||
|
||||
mode = GDT_FLAG_32_BIT;
|
||||
limit = 0xFFFFFFFF;
|
||||
|
||||
/* Setup the GDT pointer and limit */
|
||||
gp.limit = (sizeof(gdt_entry_t) * GDT_ENTRIES) - 1;
|
||||
gp.base = (size_t) &gdt;
|
||||
|
||||
/* Our NULL descriptor */
|
||||
gdt_set_gate(0, 0, 0, 0, 0);
|
||||
|
||||
/*
|
||||
* The second entry is our Code Segment. The base address
|
||||
* is 0, the limit is 4 GByte, it uses 4KByte granularity,
|
||||
* uses 32-bit opcodes, and is a Code Segment descriptor.
|
||||
*/
|
||||
gdt_set_gate(1, 0, limit,
|
||||
GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_4K_GRAN | mode);
|
||||
|
||||
/*
|
||||
* The third entry is our Data Segment. It's EXACTLY the
|
||||
* same as our code segment, but the descriptor type in
|
||||
* this entry's access byte says it's a Data Segment
|
||||
*/
|
||||
gdt_set_gate(2, 0, limit,
|
||||
GDT_FLAG_RING0 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_4K_GRAN | mode);
|
||||
|
||||
/*
|
||||
* Create code segement for userspace applications (ring 3)
|
||||
*/
|
||||
gdt_set_gate(3, 0, limit,
|
||||
GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_4K_GRAN | mode);
|
||||
|
||||
/*
|
||||
* Create data segement for userspace applications (ring 3)
|
||||
*/
|
||||
gdt_set_gate(4, 0, limit,
|
||||
GDT_FLAG_RING3 | GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG | GDT_FLAG_PRESENT,
|
||||
GDT_FLAG_4K_GRAN | mode);
|
||||
|
||||
/* set default values */
|
||||
task_state_segment.eflags = 0x1202;
|
||||
task_state_segment.ss0 = 0x10; // data segment
|
||||
task_state_segment.esp0 = 0xDEADBEEF; // invalid pseudo address
|
||||
gdt_set_gate(5, (unsigned long) (&task_state_segment), sizeof(tss_t)-1,
|
||||
GDT_FLAG_PRESENT | GDT_FLAG_TSS | GDT_FLAG_RING0, mode);
|
||||
|
||||
/* Flush out the old GDT and install the new changes! */
|
||||
gdt_flush();
|
||||
}
|
96
arch/x86/kernel/idt.c
Normal file
96
arch/x86/kernel/idt.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/kernel/idt.c
|
||||
* @brief Definitions and functions related to IDT
|
||||
*
|
||||
*
|
||||
* This file defines the interface for interrupts as like
|
||||
* structures to describe interrupt descriptor table entries.\n
|
||||
* See idt.h for flag definitions.
|
||||
*/
|
||||
|
||||
#include <eduos/string.h>
|
||||
#include <asm/idt.h>
|
||||
|
||||
/*
|
||||
* Declare an IDT of 256 entries. Although we will only use the
|
||||
* first 32 entries in this tutorial, the rest exists as a bit
|
||||
* of a trap. If any undefined IDT entry is hit, it normally
|
||||
* will cause an "Unhandled Interrupt" exception. Any descriptor
|
||||
* for which the 'presence' bit is cleared (0) will generate an
|
||||
* "Unhandled Interrupt" exception
|
||||
*/
|
||||
static idt_entry_t idt[256] = {[0 ... 255] = {0, 0, 0, 0, 0}};
|
||||
static idt_ptr_t idtp;
|
||||
|
||||
void configure_idt_entry(idt_entry_t *dest_entry, size_t base,
|
||||
unsigned short sel, unsigned char flags)
|
||||
{
|
||||
/* The interrupt routine's base address */
|
||||
dest_entry->base_lo = (base & 0xFFFF);
|
||||
dest_entry->base_hi = (base >> 16) & 0xFFFF;
|
||||
|
||||
/* The segment or 'selector' that this IDT entry will use
|
||||
* is set here, along with any access flags */
|
||||
dest_entry->sel = sel;
|
||||
dest_entry->always0 = 0;
|
||||
dest_entry->flags = flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this function to set an entry in the IDT. Alot simpler
|
||||
* than twiddling with the GDT ;)
|
||||
*/
|
||||
void idt_set_gate(unsigned char num, size_t base, unsigned short sel,
|
||||
unsigned char flags)
|
||||
{
|
||||
configure_idt_entry(&idt[num], base, sel, flags);
|
||||
}
|
||||
|
||||
extern void isrsyscall(void);
|
||||
|
||||
/* Installs the IDT */
|
||||
void idt_install(void)
|
||||
{
|
||||
static int initialized = 0;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
|
||||
/* Sets the special IDT pointer up, just like in 'gdt.c' */
|
||||
idtp.limit = (sizeof(idt_entry_t) * 256) - 1;
|
||||
idtp.base = (size_t)&idt;
|
||||
|
||||
/* Add any new ISRs to the IDT here using idt_set_gate */
|
||||
}
|
||||
|
||||
/* Points the processor's internal register to the new IDT */
|
||||
asm volatile("lidt %0" : : "m" (idtp));
|
||||
}
|
255
arch/x86/kernel/irq.c
Normal file
255
arch/x86/kernel/irq.c
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/kernel/irq.c
|
||||
* @brief Function definitions for irq.h and a standard IRQ-handler
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/errno.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/idt.h>
|
||||
#include <asm/isrs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* These are our own ISRs that point to our special IRQ handler
|
||||
* instead of the regular 'fault_handler' function
|
||||
*/
|
||||
extern void irq0(void);
|
||||
extern void irq1(void);
|
||||
extern void irq2(void);
|
||||
extern void irq3(void);
|
||||
extern void irq4(void);
|
||||
extern void irq5(void);
|
||||
extern void irq6(void);
|
||||
extern void irq7(void);
|
||||
extern void irq8(void);
|
||||
extern void irq9(void);
|
||||
extern void irq10(void);
|
||||
extern void irq11(void);
|
||||
extern void irq12(void);
|
||||
extern void irq13(void);
|
||||
extern void irq14(void);
|
||||
extern void irq15(void);
|
||||
extern void irq16(void);
|
||||
extern void irq17(void);
|
||||
extern void irq18(void);
|
||||
extern void irq19(void);
|
||||
extern void irq20(void);
|
||||
extern void irq21(void);
|
||||
extern void irq22(void);
|
||||
extern void irq23(void);
|
||||
|
||||
#define MAX_HANDLERS 256
|
||||
|
||||
/** @brief IRQ handle pointers
|
||||
*
|
||||
* This array is actually an array of function pointers. We use
|
||||
* this to handle custom IRQ handlers for a given IRQ
|
||||
*/
|
||||
static void* irq_routines[MAX_HANDLERS] = {[0 ... MAX_HANDLERS-1] = NULL };
|
||||
|
||||
/* This installs a custom IRQ handler for the given IRQ */
|
||||
int irq_install_handler(unsigned int irq, irq_handler_t handler)
|
||||
{
|
||||
if (irq >= MAX_HANDLERS)
|
||||
return -EINVAL;
|
||||
|
||||
irq_routines[irq] = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This clears the handler for a given IRQ */
|
||||
int irq_uninstall_handler(unsigned int irq)
|
||||
{
|
||||
if (irq >= MAX_HANDLERS)
|
||||
return -EINVAL;
|
||||
|
||||
irq_routines[irq] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Remapping IRQs with a couple of IO output operations
|
||||
*
|
||||
* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
|
||||
* is a problem in protected mode, because IDT entry 8 is a
|
||||
* Double Fault! Without remapping, every time IRQ0 fires,
|
||||
* you get a Double Fault Exception, which is NOT what's
|
||||
* actually happening. We send commands to the Programmable
|
||||
* Interrupt Controller (PICs - also called the 8259's) in
|
||||
* order to make IRQ0 to 15 be remapped to IDT entries 32 to
|
||||
* 47
|
||||
*/
|
||||
static int irq_remap(void)
|
||||
{
|
||||
outportb(0x20, 0x11);
|
||||
outportb(0xA0, 0x11);
|
||||
outportb(0x21, 0x20);
|
||||
outportb(0xA1, 0x28);
|
||||
outportb(0x21, 0x04);
|
||||
outportb(0xA1, 0x02);
|
||||
outportb(0x21, 0x01);
|
||||
outportb(0xA1, 0x01);
|
||||
outportb(0x21, 0x0);
|
||||
outportb(0xA1, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Remap IRQs and install ISRs in IDT
|
||||
*
|
||||
* We first remap the interrupt controllers, and then we install
|
||||
* the appropriate ISRs to the correct entries in the IDT.\n
|
||||
* This is just like installing the exception handlers
|
||||
*/
|
||||
static int irq_install(void)
|
||||
{
|
||||
irq_remap();
|
||||
|
||||
idt_set_gate(32, (size_t)irq0, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(33, (size_t)irq1, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(34, (size_t)irq2, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(35, (size_t)irq3, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(36, (size_t)irq4, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(37, (size_t)irq5, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(38, (size_t)irq6, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(39, (size_t)irq7, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(40, (size_t)irq8, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(41, (size_t)irq9, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(42, (size_t)irq10, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(43, (size_t)irq11, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(44, (size_t)irq12, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(45, (size_t)irq13, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(46, (size_t)irq14, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(47, (size_t)irq15, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(48, (size_t)irq16, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(49, (size_t)irq17, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(50, (size_t)irq18, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(51, (size_t)irq19, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(52, (size_t)irq20, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(53, (size_t)irq21, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(54, (size_t)irq22, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(55, (size_t)irq23, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irq_init(void)
|
||||
{
|
||||
idt_install();
|
||||
isrs_install();
|
||||
irq_install();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @brief Default IRQ handler
|
||||
*
|
||||
* Each of the IRQ ISRs point to this function, rather than
|
||||
* the 'fault_handler' in 'isrs.c'. The IRQ Controllers need
|
||||
* to be told when you are done servicing them, so you need
|
||||
* to send them an "End of Interrupt" command. If we use the PIC
|
||||
* instead of the APIC, we have two 8259 chips: The first one
|
||||
* exists at 0x20, the second one exists at 0xA0. If the second
|
||||
* controller (an IRQ from 8 to 15) gets an interrupt, you need to
|
||||
* acknowledge the interrupt at BOTH controllers, otherwise, you
|
||||
* only send an EOI command to the first controller. If you don't send
|
||||
* an EOI, it won't raise any more IRQs.
|
||||
*
|
||||
* Note: If we enabled the APIC, we also disabled the PIC. Afterwards,
|
||||
* we get no interrupts between 0 and 15.
|
||||
*/
|
||||
size_t** irq_handler(struct state *s)
|
||||
{
|
||||
/* This is a blank function pointer */
|
||||
void (*handler) (struct state * s);
|
||||
|
||||
/*
|
||||
* Find out if we have a custom handler to run for this
|
||||
* IRQ and then finally, run it
|
||||
*/
|
||||
if (BUILTIN_EXPECT(s->int_no < MAX_HANDLERS, 1)) {
|
||||
handler = irq_routines[s->int_no];
|
||||
if (handler)
|
||||
handler(s);
|
||||
} else kprintf("Invalid interrupt number %d\n", s->int_no);
|
||||
|
||||
/*
|
||||
* If the IDT entry that was invoked was greater-than-or-equal to 40
|
||||
* and lower than 48 (meaning IRQ8 - 15), then we need to
|
||||
* send an EOI to the slave controller of the PIC
|
||||
*/
|
||||
if (s->int_no >= 40)
|
||||
outportb(0xA0, 0x20);
|
||||
|
||||
/*
|
||||
* In either case, we need to send an EOI to the master
|
||||
* interrupt controller of the PIC, too
|
||||
*/
|
||||
outportb(0x20, 0x20);
|
||||
|
||||
// timer interrupt?
|
||||
if (s->int_no == 32)
|
||||
return scheduler(); // switch to a new task
|
||||
else if ((s->int_no >= 32) && (get_highest_priority() > current_task->prio))
|
||||
return scheduler();
|
||||
|
||||
return NULL;
|
||||
}
|
207
arch/x86/kernel/isrs.c
Normal file
207
arch/x86/kernel/isrs.c
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file arch/x86/kernel/isrs.c
|
||||
* @brief Installation of interrupt service routines and definition of fault handler.
|
||||
*
|
||||
* This file contains prototypes for the first 32 entries of the IDT,
|
||||
* an ISR installer procedure and a fault handler.\n
|
||||
*/
|
||||
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/isrs.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/idt.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* These are function prototypes for all of the exception
|
||||
* handlers: The first 32 entries in the IDT are reserved
|
||||
* by Intel and are designed to service exceptions!
|
||||
*/
|
||||
extern void isr0(void);
|
||||
extern void isr1(void);
|
||||
extern void isr2(void);
|
||||
extern void isr3(void);
|
||||
extern void isr4(void);
|
||||
extern void isr5(void);
|
||||
extern void isr6(void);
|
||||
extern void isr7(void);
|
||||
extern void isr8(void);
|
||||
extern void isr9(void);
|
||||
extern void isr10(void);
|
||||
extern void isr11(void);
|
||||
extern void isr12(void);
|
||||
extern void isr13(void);
|
||||
extern void isr14(void);
|
||||
extern void isr15(void);
|
||||
extern void isr16(void);
|
||||
extern void isr17(void);
|
||||
extern void isr18(void);
|
||||
extern void isr19(void);
|
||||
extern void isr20(void);
|
||||
extern void isr21(void);
|
||||
extern void isr22(void);
|
||||
extern void isr23(void);
|
||||
extern void isr24(void);
|
||||
extern void isr25(void);
|
||||
extern void isr26(void);
|
||||
extern void isr27(void);
|
||||
extern void isr28(void);
|
||||
extern void isr29(void);
|
||||
extern void isr30(void);
|
||||
extern void isr31(void);
|
||||
|
||||
static void fault_handler(struct state *s);
|
||||
|
||||
/*
|
||||
* This is a very repetitive function... it's not hard, it's
|
||||
* just annoying. As you can see, we set the first 32 entries
|
||||
* in the IDT to the first 32 ISRs. We can't use a for loop
|
||||
* for this, because there is no way to get the function names
|
||||
* that correspond to that given entry. We set the access
|
||||
* flags to 0x8E. This means that the entry is present, is
|
||||
* running in ring 0 (kernel level), and has the lower 5 bits
|
||||
* set to the required '14', which is represented by 'E' in
|
||||
* hex.
|
||||
*/
|
||||
void isrs_install(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
idt_set_gate(0, (size_t)isr0, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(1, (size_t)isr1, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(2, (size_t)isr2, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(3, (size_t)isr3, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(4, (size_t)isr4, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(5, (size_t)isr5, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(6, (size_t)isr6, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(7, (size_t)isr7, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(8, (size_t)isr8, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(9, (size_t)isr9, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(10, (size_t)isr10, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(11, (size_t)isr11, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(12, (size_t)isr12, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(13, (size_t)isr13, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(14, (size_t)isr14, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(15, (size_t)isr15, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(16, (size_t)isr16, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(17, (size_t)isr17, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(18, (size_t)isr18, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(19, (size_t)isr19, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(20, (size_t)isr20, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(21, (size_t)isr21, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(22, (size_t)isr22, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(23, (size_t)isr23, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(24, (size_t)isr24, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(25, (size_t)isr25, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(26, (size_t)isr26, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(27, (size_t)isr27, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(28, (size_t)isr28, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(29, (size_t)isr29, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(30, (size_t)isr30, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
idt_set_gate(31, (size_t)isr31, KERNEL_CODE_SELECTOR,
|
||||
IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP);
|
||||
|
||||
// install the default handler
|
||||
for(i=0; i<32; i++)
|
||||
irq_install_handler(i, fault_handler);
|
||||
}
|
||||
|
||||
/** @brief Exception messages
|
||||
*
|
||||
* This is a simple string array. It contains the message that
|
||||
* corresponds to each and every exception. We get the correct
|
||||
* message by accessing it like this:
|
||||
* exception_message[interrupt_number]
|
||||
*/
|
||||
static const char *exception_messages[] = {
|
||||
"Division By Zero", "Debug", "Non Maskable Interrupt",
|
||||
"Breakpoint", "Into Detected Overflow", "Out of Bounds", "Invalid Opcode",
|
||||
"No Coprocessor", "Double Fault", "Coprocessor Segment Overrun", "Bad TSS",
|
||||
"Segment Not Present", "Stack Fault", "General Protection Fault", "Page Fault",
|
||||
"Unknown Interrupt", "Coprocessor Fault", "Alignment Check", "Machine Check",
|
||||
"Reserved", "Reserved", "Reserved", "Reserved", "Reserved",
|
||||
"Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved",
|
||||
"Reserved", "Reserved" };
|
||||
|
||||
/*
|
||||
* All of our Exception handling Interrupt Service Routines will
|
||||
* point to this function. This will tell us what exception has
|
||||
* occured! Right now, we simply abort the current task.
|
||||
* All ISRs disable interrupts while they are being
|
||||
* serviced as a 'locking' mechanism to prevent an IRQ from
|
||||
* happening and messing up kernel data structures
|
||||
*/
|
||||
static void fault_handler(struct state *s)
|
||||
{
|
||||
if (s->int_no < 32) {
|
||||
kputs(exception_messages[s->int_no]);
|
||||
kprintf(" Exception (%d) at 0x%x:0x%x, error code 0x%x, eflags 0x%x\n",
|
||||
s->int_no, s->cs, s->eip, s->error, s->eflags);
|
||||
|
||||
outportb(0x20, 0x20);
|
||||
|
||||
irq_enable();
|
||||
abort();
|
||||
}
|
||||
}
|
72
arch/x86/kernel/processor.c
Normal file
72
arch/x86/kernel/processor.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/time.h>
|
||||
#include <eduos/processor.h>
|
||||
#include <eduos/tasks.h>
|
||||
|
||||
static uint32_t cpu_freq = 0;
|
||||
|
||||
uint32_t detect_cpu_frequency(void)
|
||||
{
|
||||
uint64_t start, end, diff;
|
||||
uint64_t ticks, old;
|
||||
|
||||
if (BUILTIN_EXPECT(cpu_freq > 0, 0))
|
||||
return cpu_freq;
|
||||
|
||||
old = get_clock_tick();
|
||||
|
||||
/* wait for the next time slice */
|
||||
while((ticks = get_clock_tick()) - old == 0)
|
||||
HALT;
|
||||
|
||||
rmb();
|
||||
start = rdtsc();
|
||||
/* wait a second to determine the frequency */
|
||||
while(get_clock_tick() - ticks < TIMER_FREQ)
|
||||
HALT;
|
||||
rmb();
|
||||
end = rdtsc();
|
||||
|
||||
diff = end > start ? end - start : start - end;
|
||||
cpu_freq = (uint32_t) (diff / (uint64_t) 1000000);
|
||||
|
||||
return cpu_freq;
|
||||
}
|
||||
|
||||
uint32_t get_cpu_frequency(void)
|
||||
{
|
||||
if (cpu_freq > 0)
|
||||
return cpu_freq;
|
||||
|
||||
return detect_cpu_frequency();
|
||||
}
|
||||
|
|
@ -72,15 +72,25 @@ int create_default_frame(task_t* task, entry_point_t ep, void* arg)
|
|||
* The stack must look like the stack of a task which was
|
||||
* scheduled away previously. */
|
||||
|
||||
state_size = sizeof(struct state);
|
||||
/* In legacy modes, this push is conditional and based on a change in current privilege level (CPL).*/
|
||||
state_size = sizeof(struct state) - 2*sizeof(size_t);
|
||||
stack = (size_t*) ((size_t) stack - state_size);
|
||||
|
||||
stptr = (struct state *) stack;
|
||||
memset(stptr, 0x00, state_size);
|
||||
stptr->esp = (size_t)stack + state_size;
|
||||
|
||||
stptr->int_no = 0xB16B00B5;
|
||||
stptr->error = 0xC03DB4B3;
|
||||
|
||||
/* The instruction pointer shall be set on the first function to be called
|
||||
after IRETing */
|
||||
stptr->eip = (size_t)ep;
|
||||
stptr->cs = 0x08;
|
||||
stptr->ds = stptr->es = 0x10;
|
||||
stptr->eflags = 0x1202;
|
||||
// the creation of a kernel tasks didn't change the IOPL level
|
||||
// => useresp & ss is not required
|
||||
|
||||
/* Set the task's stack pointer entry to the stack we have crafted right now. */
|
||||
task->last_stack_pointer = (size_t*)stack;
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <asm/io.h>
|
||||
#include <asm/vga.h>
|
||||
|
||||
#ifdef CONFIG_VGA
|
||||
|
||||
/*
|
||||
* These define our textpointer, our background and foreground
|
||||
* colors (attributes), and x and y cursor coordinates
|
||||
|
@ -233,3 +235,5 @@ void vga_init(void)
|
|||
textmemptr = (unsigned short *)VIDEO_MEM_ADDR;
|
||||
vga_clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,12 +34,17 @@ extern "C" {
|
|||
|
||||
#define EDUOS_VERSION "0.1"
|
||||
#define MAX_TASKS 16
|
||||
#define VIDEO_MEM_ADDR 0xB8000 // the video memora address
|
||||
#define TIMER_FREQ 100 /* in HZ */
|
||||
#define CLOCK_TICK_RATE 1193182 /* 8254 chip's internal oscillator frequency */
|
||||
#define VIDEO_MEM_ADDR 0xB8000 // the video memora address
|
||||
#define CACHE_LINE 64
|
||||
#define KERNEL_STACK_SIZE (8*1024)
|
||||
#define PAGE_SHIFT 12
|
||||
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
#define CONFIG_VGA
|
||||
|
||||
#define BUILTIN_EXPECT(exp, b) __builtin_expect((exp), (b))
|
||||
//#define BUILTIN_EXPECT(exp, b) (exp)
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
|
|
|
@ -46,6 +46,10 @@ extern "C" {
|
|||
/// represents a task identifier
|
||||
typedef unsigned int tid_t;
|
||||
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||
#define PAGE_MASK ~(PAGE_SIZE - 1)
|
||||
#define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
|
||||
|
||||
struct task;
|
||||
/// pointer to the current (running) task
|
||||
extern struct task* current_task;
|
||||
|
|
|
@ -44,6 +44,16 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Task switcher
|
||||
*
|
||||
* Timer-interrupted use of this function for task switching
|
||||
*
|
||||
* @return
|
||||
* - 0 no context switch
|
||||
* - !0 address of the old stack pointer
|
||||
*/
|
||||
size_t** scheduler(void);
|
||||
|
||||
/** @brief Initialize the multitasking subsystem
|
||||
*
|
||||
* This procedure sets the current task to the
|
||||
|
@ -68,6 +78,14 @@ int multitasking_init(void);
|
|||
*/
|
||||
int create_kernel_task(tid_t* id, entry_point_t ep, void* args, uint8_t prio);
|
||||
|
||||
/** @brief determine the highest priority of all tasks, which are ready
|
||||
*
|
||||
* @return
|
||||
* - return highest priority
|
||||
* - if no task is ready, the function returns an invalid value (> MAX_PRIO)
|
||||
*/
|
||||
uint32_t get_highest_priority(void);
|
||||
|
||||
/** @brief Call to rescheduling
|
||||
*
|
||||
* This is a purely assembled procedure for rescheduling
|
||||
|
@ -94,6 +112,9 @@ int wakeup_task(tid_t);
|
|||
*/
|
||||
int block_current_task(void);
|
||||
|
||||
/** @brief Abort current task */
|
||||
void NORETURN abort(void);
|
||||
|
||||
/** @brief This function shall be called by leaving kernel level tasks */
|
||||
void NORETURN leave_kernel_task(void);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#define __TASKS_TYPES_H__
|
||||
|
||||
#include <eduos/stddef.h>
|
||||
#include <eduos/spinlock_types.h>
|
||||
#include <asm/tasks_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -95,6 +96,8 @@ typedef struct {
|
|||
uint32_t prio_bitmap;
|
||||
/// a queue for each priority
|
||||
task_list_t queue[MAX_PRIO-1];
|
||||
/// lock for this runqueue
|
||||
spinlock_irqsave_t lock;
|
||||
} readyqueues_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
56
include/eduos/time.h
Normal file
56
include/eduos/time.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Stefan Lankes
|
||||
* @file include/eduos/time.h
|
||||
* @brief Time related functions
|
||||
*/
|
||||
|
||||
#ifndef __TIME_H__
|
||||
#define __TIME_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Initialize Timer interrupts
|
||||
*
|
||||
* This procedure installs IRQ handlers for timer interrupts
|
||||
*/
|
||||
int timer_init(void);
|
||||
|
||||
/** @brief Returns the current number of ticks.
|
||||
* @return Current number of ticks
|
||||
*/
|
||||
uint64_t get_clock_tick(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -28,10 +28,13 @@
|
|||
#include <eduos/stddef.h>
|
||||
#include <eduos/stdio.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/time.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/processor.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/semaphore.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irqflags.h>
|
||||
|
||||
/*
|
||||
* Note that linker symbols are not variables, they have no memory allocated for
|
||||
|
@ -48,13 +51,10 @@ static sem_t sem;
|
|||
|
||||
static int foo(void* arg)
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
for(i=0; i<5; i++) {
|
||||
sem_wait(&sem);
|
||||
for(i=0; i<10; i++) {
|
||||
kprintf("hello from %s\n", (char*) arg);
|
||||
reschedule();
|
||||
sem_post(&sem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -65,6 +65,9 @@ static int eduos_init(void)
|
|||
// initialize .bss section
|
||||
memset((void*)&bss_start, 0x00, ((size_t) &bss_end - (size_t) &bss_start));
|
||||
|
||||
system_init();
|
||||
irq_init();
|
||||
timer_init();
|
||||
koutput_init();
|
||||
multitasking_init();
|
||||
|
||||
|
@ -80,13 +83,17 @@ int main(void)
|
|||
kprintf("This is eduOS %s Build %u, %u\n", EDUOS_VERSION, &__BUILD_DATE, &__BUILD_TIME);
|
||||
kprintf("Kernel starts at %p and ends at %p\n", &kernel_start, &kernel_end);
|
||||
|
||||
irq_enable();
|
||||
system_calibration();
|
||||
|
||||
kprintf("Processor frequency: %u MHz\n", get_cpu_frequency());
|
||||
|
||||
sem_init(&sem, 1);
|
||||
create_kernel_task(&id1, foo, "foo1", NORMAL_PRIO);
|
||||
create_kernel_task(&id2, foo, "foo2", NORMAL_PRIO);
|
||||
reschedule();
|
||||
|
||||
while(1) {
|
||||
NOP8;
|
||||
HALT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -30,10 +30,9 @@
|
|||
#include <eduos/stdio.h>
|
||||
#include <eduos/tasks.h>
|
||||
#include <eduos/tasks_types.h>
|
||||
#include <eduos/spinlock.h>
|
||||
#include <eduos/errno.h>
|
||||
|
||||
extern void* default_stack_pointer;
|
||||
|
||||
/** @brief Array of task structures (aka PCB)
|
||||
*
|
||||
* A task's id will be its position in this array.
|
||||
|
@ -42,9 +41,12 @@ static task_t task_table[MAX_TASKS] = { \
|
|||
[0] = {0, TASK_IDLE, NULL, NULL, 0, NULL, NULL}, \
|
||||
[1 ... MAX_TASKS-1] = {0, TASK_INVALID, NULL, NULL, 0, NULL, NULL}};
|
||||
|
||||
static readyqueues_t readyqueues = { task_table+0, NULL, 0, 0, {[0 ... MAX_PRIO-2] = {NULL, NULL}}};
|
||||
static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT;
|
||||
|
||||
static readyqueues_t readyqueues = {task_table+0, NULL, 0, 0, {[0 ... MAX_PRIO-2] = {NULL, NULL}}, SPINLOCK_IRQSAVE_INIT};
|
||||
|
||||
task_t* current_task = task_table+0;
|
||||
extern const void boot_stack;
|
||||
|
||||
/** @brief helper function for the assembly code to determine the current task
|
||||
* @return Pointer to the task_t structure of current task
|
||||
|
@ -54,6 +56,11 @@ task_t* get_current_task(void)
|
|||
return current_task;
|
||||
}
|
||||
|
||||
uint32_t get_highest_priority(void)
|
||||
{
|
||||
return msb(readyqueues.prio_bitmap);
|
||||
}
|
||||
|
||||
int multitasking_init(void)
|
||||
{
|
||||
if (BUILTIN_EXPECT(task_table[0].status != TASK_IDLE, 0)) {
|
||||
|
@ -62,7 +69,7 @@ int multitasking_init(void)
|
|||
}
|
||||
|
||||
task_table[0].prio = IDLE_PRIO;
|
||||
task_table[0].stack = default_stack_pointer - 8192;
|
||||
task_table[0].stack = (void*) &boot_stack;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -72,6 +79,8 @@ void finish_task_switch(void)
|
|||
task_t* old;
|
||||
uint8_t prio;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
|
||||
if ((old = readyqueues.old_task) != NULL) {
|
||||
if (old->status == TASK_INVALID) {
|
||||
old->stack = NULL;
|
||||
|
@ -92,6 +101,8 @@ void finish_task_switch(void)
|
|||
readyqueues.prio_bitmap |= (1 << prio);
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
}
|
||||
|
||||
/** @brief A procedure to be called by
|
||||
|
@ -105,9 +116,14 @@ static void NORETURN do_exit(int arg)
|
|||
curr_task->status = TASK_FINISHED;
|
||||
reschedule();
|
||||
|
||||
// decrease the number of active tasks
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
readyqueues.nr_tasks--;
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
|
||||
kprintf("Kernel panic: scheduler found no valid task\n");
|
||||
while(1) {
|
||||
NOP8;
|
||||
HALT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,6 +135,11 @@ void NORETURN leave_kernel_task(void) {
|
|||
do_exit(result);
|
||||
}
|
||||
|
||||
/** @brief Aborting a task is like exiting it with result -1 */
|
||||
void NORETURN abort(void) {
|
||||
do_exit(-1);
|
||||
}
|
||||
|
||||
/** @brief Create a task with a specific entry point
|
||||
*
|
||||
* @param id Pointer to a tid_t struct were the id shall be set
|
||||
|
@ -143,6 +164,8 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio)
|
|||
if (BUILTIN_EXPECT(prio > MAX_PRIO, 0))
|
||||
return -EINVAL;
|
||||
|
||||
spinlock_irqsave_lock(&table_lock);
|
||||
|
||||
for(i=0; i<MAX_TASKS; i++) {
|
||||
if (task_table[i].status == TASK_INVALID) {
|
||||
task_table[i].id = i;
|
||||
|
@ -157,6 +180,7 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio)
|
|||
ret = create_default_frame(task_table+i, ep, arg);
|
||||
|
||||
// add task in the readyqueues
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
readyqueues.prio_bitmap |= (1 << prio);
|
||||
readyqueues.nr_tasks++;
|
||||
if (!readyqueues.queue[prio-1].first) {
|
||||
|
@ -169,10 +193,13 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio)
|
|||
readyqueues.queue[prio-1].last->next = task_table+i;
|
||||
readyqueues.queue[prio-1].last = task_table+i;
|
||||
}
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spinlock_irqsave_unlock(&table_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -195,6 +222,9 @@ int wakeup_task(tid_t id)
|
|||
task_t* task;
|
||||
uint32_t prio;
|
||||
int ret = -EINVAL;
|
||||
uint8_t flags;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
|
||||
task = task_table + id;
|
||||
prio = task->prio;
|
||||
|
@ -203,6 +233,7 @@ int wakeup_task(tid_t id)
|
|||
task->status = TASK_READY;
|
||||
ret = 0;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
// increase the number of ready tasks
|
||||
readyqueues.nr_tasks++;
|
||||
|
||||
|
@ -217,8 +248,11 @@ int wakeup_task(tid_t id)
|
|||
readyqueues.queue[prio-1].last->next = task;
|
||||
readyqueues.queue[prio-1].last = task;
|
||||
}
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
}
|
||||
|
||||
irq_nested_enable(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -235,6 +269,9 @@ int block_current_task(void)
|
|||
tid_t id;
|
||||
uint32_t prio;
|
||||
int ret = -EINVAL;
|
||||
uint8_t flags;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
|
||||
id = current_task->id;
|
||||
prio = current_task->prio;
|
||||
|
@ -243,6 +280,7 @@ int block_current_task(void)
|
|||
task_table[id].status = TASK_BLOCKED;
|
||||
ret = 0;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
// reduce the number of ready tasks
|
||||
readyqueues.nr_tasks--;
|
||||
|
||||
|
@ -262,8 +300,11 @@ int block_current_task(void)
|
|||
// No valid task in queue => update prio_bitmap
|
||||
if (!readyqueues.queue[prio-1].first)
|
||||
readyqueues.prio_bitmap &= ~(1 << prio);
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
}
|
||||
|
||||
irq_nested_enable(flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -274,6 +315,8 @@ size_t** scheduler(void)
|
|||
|
||||
orig_task = current_task;
|
||||
|
||||
spinlock_irqsave_lock(&readyqueues.lock);
|
||||
|
||||
/* signalizes that this task could be reused */
|
||||
if (current_task->status == TASK_FINISHED) {
|
||||
current_task->status = TASK_INVALID;
|
||||
|
@ -312,6 +355,8 @@ size_t** scheduler(void)
|
|||
}
|
||||
|
||||
get_task_out:
|
||||
spinlock_irqsave_unlock(&readyqueues.lock);
|
||||
|
||||
if (current_task != orig_task) {
|
||||
//kprintf("schedule from %u to %u with prio %u\n", orig_task->id, current_task->id, (uint32_t)current_task->prio);
|
||||
|
||||
|
@ -324,6 +369,10 @@ get_task_out:
|
|||
void reschedule(void)
|
||||
{
|
||||
size_t** stack;
|
||||
uint8_t flags;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
if ((stack = scheduler()))
|
||||
switch_context(stack);
|
||||
irq_nested_enable(flags);
|
||||
}
|
||||
|
|
|
@ -28,28 +28,39 @@
|
|||
#include <eduos/stdio.h>
|
||||
#include <eduos/string.h>
|
||||
#include <eduos/stdarg.h>
|
||||
#include <eduos/spinlock.h>
|
||||
#include <asm/vga.h>
|
||||
|
||||
static spinlock_irqsave_t olock = SPINLOCK_IRQSAVE_INIT;
|
||||
|
||||
int koutput_init(void)
|
||||
{
|
||||
#ifdef CONFIG_VGA
|
||||
vga_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kputchar(int c)
|
||||
{
|
||||
spinlock_irqsave_lock(&olock);
|
||||
#ifdef CONFIG_VGA
|
||||
vga_putchar(c);
|
||||
#endif
|
||||
spinlock_irqsave_unlock(&olock);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int kputs(const char *str)
|
||||
{
|
||||
#ifdef CONFIG_VGA
|
||||
int i;
|
||||
|
||||
for(i=0; str[i] != '\0'; i++)
|
||||
vga_putchar((int) str[i]);
|
||||
|
||||
return i;
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue