[GOOD] BUILD 0.1.0.450 DATE 8/29/2011 AT 10:30 AM

====================================================
+ Changed 'align 0x4' line above multiboot header in loader.asm to
'align 4'
+ Removed -e option for echo in build.sh
+ Modified build.sh for linux
+ Fixed triple fault when enabling paging
+ Fixed page faults at memory manager initialization
+ Fixed 'mem' console function
+ Added more info about page fault at crash screen
+ Added Panic() macro
+ Added verbose mode for memory manager

[ BAD] BUILD 0.1.0.390 DATE 8/27/2011 AT 10:54 PM
====================================================
+ Added stdlib routines, separated in different files
+ Rewritten physical memory manager
+ Added virtual mem manager
+ Added memory allocation/freeing
+ Added memory library
+ Added temporary allocation (at end of kernel), until paging is started
- Removed functionality from debug console function 'mem'
- Removed system.h, the one remaining function now in stdio.h
This commit is contained in:
2021-09-14 18:48:57 +03:00
parent b6ddeca1c3
commit 913e65b856
326 changed files with 6990 additions and 12229 deletions

View File

@ -0,0 +1,23 @@
; GLOBAL DESCRIPTOR TABLE
;
;
bits 32
; !!! GDT !!!
; 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.
global GdtFlush ; Allows the C code to link to this
extern gp ; Says that 'gp' is in another file
GdtFlush:
lgdt [gp] ; Load the GDT with our 'gp' which is a special pointer
mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:flush2 ; 0x08 is the offset to our code segment: Far jump!
flush2:
ret ; Returns back to the C code!

74
Kernel/hal/cpu/gdt.c Normal file
View File

@ -0,0 +1,74 @@
/******************************************************************
* gdt.c - GLOBAL DESCRIPTOR TABLE *
* Contains function prototypes for setting up the GDT *
******************************************************************/
#define MAX_DESCRIPTORS 5
#include "gdt.h"
/* Our GDT, with 3 entries, and finally our special GDT pointer */
struct GdtEntry gdt[MAX_DESCRIPTORS];
struct GdtPointer gp;
/* Setup a descriptor in the Global Descriptor Table */
void GdtSetGate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
/* Sanity check */
if (num >= MAX_DESCRIPTORS) return;
/* Setup the descriptor base address */
gdt[num].base_low = (base & 0xFFFF);
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].base_high = (base >> 24) & 0xFF;
/* Setup the descriptor limits */
gdt[num].limit_low = (limit & 0xFFFF);
gdt[num].granularity = ((limit >> 16) & 0x0F);
/* Finally, set up the granularity and access flags */
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access = access;
}
struct GdtEntry* GdtGetGate(int num)
{
if (num>MAX_DESCRIPTORS) return 0;
return &gdt[num];
}
/* Should be called by main. This will setup the special GDT
* pointer, set up the first 3 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 GdtInstall()
{
/* Setup the GDT pointer and limit */
gp.limit = (sizeof(struct GdtEntry) * 3) - 1;
gp.base = (unsigned int)&gdt;
/* Our NULL descriptor */
GdtSetGate(0, 0, 0, 0, 0);
/* The second entry is our Code Segment. The base address
* is 0, the limit is 4GBytes, it uses 4KByte granularity,
* uses 32-bit opcodes, and is a Code Segment descriptor.
* Please check the table above in the tutorial in order
* to see exactly what each value means */
GdtSetGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
/* 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 */
GdtSetGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
/* User mode Code segment*/
GdtSetGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
/* User mode data segment*/
GdtSetGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
/* Flush out the old GDT and install the new changes! */
GdtFlush();
}

38
Kernel/hal/cpu/gdt.h Normal file
View File

@ -0,0 +1,38 @@
/******************************************************************
* gdt.h - GLOBAL DESCRIPTOR TABLE *
* Contains structures and function declarations for GDT *
******************************************************************/
#ifndef __GDT_H
#define __GDT_H
/* Defines a GDT entry. We say packed, because it prevents the
* compiler from doing things that it thinks is best: Prevent
* compiler "optimization" by packing */
struct GdtEntry
{
unsigned short limit_low;
unsigned short base_low;
unsigned char base_middle;
unsigned char access;
unsigned char granularity;
unsigned char base_high;
} __attribute__((packed));
/* Special pointer which includes the limit: The max bytes
* taken up by the GDT, minus 1. Again, this NEEDS to be packed */
struct GdtPointer
{
unsigned short limit;
unsigned int base;
} __attribute__((packed));
/* This will be a function in start.asm. We use this to properly
* reload the new segment registers */
extern void GdtInstall();
extern void GdtFlush();
extern void GdtSetGate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran);
extern struct GdtEntry* GdtGetGate(int num);
#endif

View File

@ -0,0 +1,9 @@
bits 32
; !!! IDT !!!
; Loads the IDT defined in '_idtp'
global IdtLoad
extern idtp
IdtLoad:
lidt [idtp]
ret

45
Kernel/hal/cpu/idt.c Normal file
View File

@ -0,0 +1,45 @@
/******************************************************************
* idt.h - INTERRUPT DESCRIPTOR TABLE *
* Contains structures and function declarations for IDT *
******************************************************************/
#include <stdlib.h>
#include "idt.h"
extern void IdtLoad();
/* Declare an IDT of 256 entries. */
struct IdtEntry idt[256];
struct IdtPointer idtp;
/* Use this function to set an entry in the IDT. Alot simpler
* than twiddling with the GDT ;) */
void IdtSetGate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags)
{
/* The interrupt routine's base address */
idt[num].base_lo = (base & 0xFFFF);
idt[num].base_hi = (base >> 16) & 0xFFFF;
/* The segment or 'selector' that this IDT entry will use
* is set here, along with any access flags */
idt[num].sel = sel;
idt[num].always0 = 0;
idt[num].flags = flags;
}
struct IdtEntry* IdtGetGate(unsigned char num)
{
return &idt[num];
}
/* Installs the IDT */
void IdtInstall()
{
/* Sets the special IDT pointer up, just like in 'gdt.c' */
idtp.limit = (sizeof (struct IdtEntry) * 256) - 1;
idtp.base = (unsigned int)&idt;
/* Clear out the entire IDT, initializing it to zeros */
memset (&idt, 0, sizeof(struct IdtEntry) * 256);
/* Points the processor's internal register to the new IDT */
IdtLoad();
}

31
Kernel/hal/cpu/idt.h Normal file
View File

@ -0,0 +1,31 @@
/******************************************************************
* idt.h - INTERRUPT DESCRIPTOR TABLE *
* Contains structures and function declarations for IDT *
******************************************************************/
#ifndef __IDT_H
#define __IDT_H
/* Defines an IDT entry */
struct IdtEntry
{
unsigned short base_lo;
unsigned short sel;
unsigned char always0;
unsigned char flags;
unsigned short base_hi;
} __attribute__((packed));
struct IdtPointer
{
unsigned short limit;
unsigned int base;
} __attribute__((packed));
/* This exists in 'start.asm', and is used to load our IDT */
extern void IdtSetGate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags);
extern struct IdtEntry* IdtGetGate(unsigned char num);
extern void IdtInstall();
#endif

159
Kernel/hal/cpu/irq-asm.asm Normal file
View File

@ -0,0 +1,159 @@
bits 32
; !!! IRQ !!!
global Irq_0
global Irq_1
global Irq_2
global Irq_3
global Irq_4
global Irq_5
global Irq_6
global Irq_7
global Irq_8
global Irq_9
global Irq_10
global Irq_11
global Irq_12
global Irq_13
global Irq_14
global Irq_15
; 32: IRQ0
Irq_0:
cli
push byte 0
push byte 32; Note that these don't push an error code on the stack:
; We need to push a dummy error code
jmp irq_common_stub
; 33: IRQ1
Irq_1:
cli
push byte 0
push byte 33
jmp irq_common_stub
; 34: IRQ2
Irq_2:
cli
push byte 0
push byte 34
jmp irq_common_stub
; 35: IRQ3
Irq_3:
cli
push byte 0
push byte 35
jmp irq_common_stub
; 36: IRQ4
Irq_4:
cli
push byte 0
push byte 36
jmp irq_common_stub
; 37: IRQ5
Irq_5:
cli
push byte 0
push byte 37
jmp irq_common_stub
; 38: IRQ6
Irq_6:
cli
push byte 0
push byte 38
jmp irq_common_stub
; 39: IRQ7
Irq_7:
cli
push byte 0
push byte 39
jmp irq_common_stub
; 40: IRQ8
Irq_8:
cli
push byte 0
push byte 40
jmp irq_common_stub
; 41: IRQ9
Irq_9:
cli
push byte 0
push byte 41
jmp irq_common_stub
; 42: IRQ10
Irq_10:
cli
push byte 0
push byte 42
jmp irq_common_stub
; 43: IRQ11
Irq_11:
cli
push byte 0
push byte 43
jmp irq_common_stub
; 44: IRQ12
Irq_12:
cli
push byte 0
push byte 44
jmp irq_common_stub
; 45: IRQ13
Irq_13:
cli
push byte 0
push byte 45
jmp irq_common_stub
; 46: IRQ14
Irq_14:
cli
push byte 0
push byte 46
jmp irq_common_stub
; 47: IRQ15
Irq_15:
cli
push byte 0
push byte 47
jmp irq_common_stub
extern IrqHandler
; This is a stub that we have created for IRQ based ISRs. This calls
; 'Irq__handler' in our C code. We need to create this in an 'irq.c'
irq_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp
push eax
mov eax, IrqHandler
call eax
pop eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8
iret

91
Kernel/hal/cpu/irq.c Normal file
View File

@ -0,0 +1,91 @@
#include <stdio.h>
#include "pic.h"
#include "irq.h"
#include "idt.h"
/* These are own ISRs that point to our special IRQ handler
* instead of the regular 'fault_handler' function */
extern void Irq_0();
extern void Irq_1();
extern void Irq_2();
extern void Irq_3();
extern void Irq_4();
extern void Irq_5();
extern void Irq_6();
extern void Irq_7();
extern void Irq_8();
extern void Irq_9();
extern void Irq_10();
extern void Irq_11();
extern void Irq_12();
extern void Irq_13();
extern void Irq_14();
extern void Irq_15();
/* This array is actually an array of function pointers. We use
* this to handle custom IRQ handlers for a given IRQ */
void *IrqRoutines[16] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
/* This installs a custom IRQ handler for the given IRQ */
void IrqInstallHandler (int irq, void (*handler)(_RegsStack32 *r))
{
IrqRoutines[irq] = handler;
}
void IrqUninstallHandler (int irq)
{
IrqRoutines[irq] = 0;
}
/* We first remap the interrupt controllers, and then we install
* the appropriate ISRs to the correct entries in the IDT. This
* is just like installing the exception handlers */
void IrqInstall()
{
PicRemap(32,40);
IdtSetGate(32, (unsigned)Irq_0, 0x08, 0x8E);
IdtSetGate(33, (unsigned)Irq_1, 0x08, 0x8E);
IdtSetGate(34, (unsigned)Irq_2, 0x08, 0x8E);
IdtSetGate(35, (unsigned)Irq_3, 0x08, 0x8E);
IdtSetGate(36, (unsigned)Irq_4, 0x08, 0x8E);
IdtSetGate(37, (unsigned)Irq_5, 0x08, 0x8E);
IdtSetGate(38, (unsigned)Irq_6, 0x08, 0x8E);
IdtSetGate(39, (unsigned)Irq_7, 0x08, 0x8E);
IdtSetGate(40, (unsigned)Irq_8, 0x08, 0x8E);
IdtSetGate(41, (unsigned)Irq_9, 0x08, 0x8E);
IdtSetGate(42, (unsigned)Irq_10, 0x08, 0x8E);
IdtSetGate(43, (unsigned)Irq_11, 0x08, 0x8E);
IdtSetGate(44, (unsigned)Irq_12, 0x08, 0x8E);
IdtSetGate(45, (unsigned)Irq_13, 0x08, 0x8E);
IdtSetGate(46, (unsigned)Irq_14, 0x08, 0x8E);
IdtSetGate(47, (unsigned)Irq_15, 0x08, 0x8E);
}
// Default IRQ handler, launches other handler if installed.
// Also sends end-of-interrupt messages to PIC
void IrqHandler (_RegsStack32 *r)
{
/* This is a blank function pointer */
void (*handler)(_RegsStack32 *r);
/* Find out if we have a custom handler to run for this
* IRQ, and then finally, run it */
handler = IrqRoutines[r->int_no - 32];
if (handler) handler(r);
/* If the IDT entry that was invoked was greater than 40
* (meaning IRQ8 - 15), then we need to send an EOI to
* the slave controller */
if (r->int_no >=40) outportb(0xA0, 0x20);
/* In either case, we need to send an EOI to the master
* interrupt controller too */
outportb(0x20, 0x20);
}

10
Kernel/hal/cpu/irq.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __IRQ_H
#define __IRQ_H
#include <stdio.h>
extern void IrqInstallHandler (int irq, void (*handler)(_RegsStack32 *r));
extern void IrqUninstallHandler (int irq);
extern void IrqInstall();
#endif

217
Kernel/hal/cpu/isrs-asm.asm Normal file
View File

@ -0,0 +1,217 @@
bits 32
; !!! ISRs !!!
global isr_exception_0
global isr_exception_1
global isr_exception_2
global isr_exception_3
global isr_exception_4
global isr_exception_5
global isr_exception_6
global isr_exception_7
global isr_exception_8
global isr_exception_9
global isr_exception_10
global isr_exception_11
global isr_exception_12
global isr_exception_13
global isr_exception_14
global isr_exception_15
global isr_exception_16
global isr_exception_17
global isr_exception_18
global isr_exception_19
global isr_exception_20
global isr_exception_21
global isr_exception_22
global isr_exception_23
global isr_exception_24
global isr_exception_25
global isr_exception_26
global isr_exception_27
global isr_exception_28
global isr_exception_29
global isr_exception_30
global isr_exception_31
isr_exception_0:
cli
push byte 0; A normal ISR stub that pops a dummy error code to keep a
; uniform stack frame
push byte 0
jmp isr_common_stub
isr_exception_1:
cli
push byte 0
push byte 1
jmp isr_common_stub
isr_exception_2:
cli
push byte 0
push byte 2
jmp isr_common_stub
isr_exception_3:
cli
push byte 0
push byte 3
jmp isr_common_stub
isr_exception_4:
cli
push byte 0
push byte 4
jmp isr_common_stub
isr_exception_5:
cli
push byte 0
push byte 5
jmp isr_common_stub
isr_exception_6:
cli
push byte 0
push byte 6
jmp isr_common_stub
isr_exception_7:
cli
push byte 0
push byte 7
jmp isr_common_stub
isr_exception_8:
cli
push byte 8
jmp isr_common_stub
isr_exception_9:
cli
push byte 0
push byte 9
jmp isr_common_stub
isr_exception_10:
cli
push byte 10
jmp isr_common_stub
isr_exception_11:
cli
push byte 11
jmp isr_common_stub
isr_exception_12:
cli
push byte 12
jmp isr_common_stub
isr_exception_13:
cli
push byte 13
jmp isr_common_stub
isr_exception_14:
cli
push byte 14
jmp isr_common_stub
isr_exception_15:
cli
push byte 0
push byte 15
jmp isr_common_stub
isr_exception_16:
cli
push byte 0
push byte 16
jmp isr_common_stub
isr_exception_17:
cli
push byte 0
push byte 17
jmp isr_common_stub
isr_exception_18:
cli
push byte 0
push byte 18
jmp isr_common_stub
isr_exception_19:
cli
push byte 0
push byte 19
jmp isr_common_stub
isr_exception_20:
cli
push byte 0
push byte 20
jmp isr_common_stub
isr_exception_21:
cli
push byte 0
push byte 21
jmp isr_common_stub
isr_exception_22:
cli
push byte 0
push byte 22
jmp isr_common_stub
isr_exception_23:
cli
push byte 0
push byte 23
jmp isr_common_stub
isr_exception_24:
cli
push byte 0
push byte 24
jmp isr_common_stub
isr_exception_25:
cli
push byte 0
push byte 25
jmp isr_common_stub
isr_exception_26:
cli
push byte 0
push byte 26
jmp isr_common_stub
isr_exception_27:
cli
push byte 0
push byte 27
jmp isr_common_stub
isr_exception_28:
cli
push byte 0
push byte 28
jmp isr_common_stub
isr_exception_29:
cli
push byte 0
push byte 29
jmp isr_common_stub
isr_exception_30:
cli
push byte 0
push byte 30
jmp isr_common_stub
isr_exception_31:
cli
push byte 0
push byte 31
jmp isr_common_stub
extern IsrsFaultHandler
isr_common_stub:
pusha
push ds
push es
push fs
push gs
mov ax, 0x10 ; Load the Kernel Data Segment descriptor!
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax, esp ; Push us the stack
push eax
mov eax, IsrsFaultHandler
call eax ; A special call, preserves the 'eip' register
pop eax
pop gs
pop fs
pop es
pop ds
popa
add esp, 8 ; Cleans up the pushed error code and pushed ISR number
iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP!

114
Kernel/hal/cpu/isrs.c Normal file
View File

@ -0,0 +1,114 @@
#include <debugio.h>
#include "isrs.h"
#include "idt.h"
// Assembly coded
extern void isr_exception_0();
extern void isr_exception_1();
extern void isr_exception_2();
extern void isr_exception_3();
extern void isr_exception_4();
extern void isr_exception_5();
extern void isr_exception_6();
extern void isr_exception_7();
extern void isr_exception_8();
extern void isr_exception_9();
extern void isr_exception_10();
extern void isr_exception_11();
extern void isr_exception_12();
extern void isr_exception_13();
extern void isr_exception_14();
extern void isr_exception_15();
extern void isr_exception_16();
extern void isr_exception_17();
extern void isr_exception_18();
extern void isr_exception_19();
extern void isr_exception_20();
extern void isr_exception_21();
extern void isr_exception_22();
extern void isr_exception_23();
extern void isr_exception_24();
extern void isr_exception_25();
extern void isr_exception_26();
extern void isr_exception_27();
extern void isr_exception_28();
extern void isr_exception_29();
extern void isr_exception_30();
extern void isr_exception_31();
void* IdtFaultHandlers[32] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
void IsrsInstall()
{
IdtSetGate(0, (unsigned)isr_exception_0, 0x08, 0x8E);
IdtSetGate(1, (unsigned)isr_exception_1, 0x08, 0x8E);
IdtSetGate(2, (unsigned)isr_exception_2, 0x08, 0x8E);
IdtSetGate(3, (unsigned)isr_exception_3, 0x08, 0x8E);
IdtSetGate(4, (unsigned)isr_exception_4, 0x08, 0x8E);
IdtSetGate(5, (unsigned)isr_exception_5, 0x08, 0x8E);
IdtSetGate(6, (unsigned)isr_exception_6, 0x08, 0x8E);
IdtSetGate(7, (unsigned)isr_exception_7, 0x08, 0x8E);
IdtSetGate(8, (unsigned)isr_exception_8, 0x08, 0x8E);
IdtSetGate(9, (unsigned)isr_exception_9, 0x08, 0x8E);
IdtSetGate(10, (unsigned)isr_exception_10, 0x08, 0x8E);
IdtSetGate(11, (unsigned)isr_exception_11, 0x08, 0x8E);
IdtSetGate(12, (unsigned)isr_exception_12, 0x08, 0x8E);
IdtSetGate(13, (unsigned)isr_exception_13, 0x08, 0x8E);
IdtSetGate(14, (unsigned)isr_exception_14, 0x08, 0x8E);
IdtSetGate(15, (unsigned)isr_exception_15, 0x08, 0x8E);
IdtSetGate(16, (unsigned)isr_exception_16, 0x08, 0x8E);
IdtSetGate(17, (unsigned)isr_exception_17, 0x08, 0x8E);
IdtSetGate(18, (unsigned)isr_exception_18, 0x08, 0x8E);
IdtSetGate(19, (unsigned)isr_exception_19, 0x08, 0x8E);
IdtSetGate(20, (unsigned)isr_exception_20, 0x08, 0x8E);
IdtSetGate(21, (unsigned)isr_exception_21, 0x08, 0x8E);
IdtSetGate(22, (unsigned)isr_exception_22, 0x08, 0x8E);
IdtSetGate(23, (unsigned)isr_exception_23, 0x08, 0x8E);
IdtSetGate(24, (unsigned)isr_exception_24, 0x08, 0x8E);
IdtSetGate(25, (unsigned)isr_exception_25, 0x08, 0x8E);
IdtSetGate(26, (unsigned)isr_exception_26, 0x08, 0x8E);
IdtSetGate(27, (unsigned)isr_exception_27, 0x08, 0x8E);
IdtSetGate(28, (unsigned)isr_exception_28, 0x08, 0x8E);
IdtSetGate(29, (unsigned)isr_exception_29, 0x08, 0x8E);
IdtSetGate(30, (unsigned)isr_exception_30, 0x08, 0x8E);
IdtSetGate(31, (unsigned)isr_exception_31, 0x08, 0x8E);
}
void IsrsInstallHandler(int interr, void (*function)(_RegsStack32 *r))
{
if (interr < 32) IdtFaultHandlers[interr] = function;
}
void IsrsUninstallHandler(int interr)
{
if (interr < 32) IdtFaultHandlers[interr] = 0;
}
extern void CrashMessage(_RegsStack32 *r);
// Default fault handler; calls other handlers, or displays error message.
void IsrsFaultHandler(_RegsStack32 *r)
{
/* Is this a fault whose number is from 0 to 31? */
if (r->int_no < 32)
{
void (*func)(_RegsStack32 *r);
func = IdtFaultHandlers[r->int_no];
// Halt system if unhandled
if (!func) {
CrashMessage(r);
asm ("cli");
asm ("hlt");
}
else (*func)(r);
}
}

10
Kernel/hal/cpu/isrs.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef __ISRS_H_
#define __ISRS_H_
#include <types.h>
extern void IsrsInstall();
extern void IsrsInstallHandler(int interr, void (*function)(_RegsStack32 *r));
extern void IsrsUninstallHandler(int interr);
#endif

23
Kernel/hal/cpu/pic.c Normal file
View File

@ -0,0 +1,23 @@
#include <stdio.h>
#include "pic.h"
void PicRemap(int pic1, int pic2)
{
// Send ICW1
outportb(0x20, 0x11);
outportb(0xA0, 0x11);
// send ICW2
outportb(0x21, pic1); // remap pics
outportb(0xA1, pic2);
// send ICW3
outportb(0x21, 4);
outportb(0xA1, 2);
// Send ICW4
outportb(0x21, 0x01);
outportb(0xA1, 0x01);
outportb(0x21, 0x00);
}

6
Kernel/hal/cpu/pic.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef _PIC_H
#define _PIC_H
extern void PicRemap(int pic1, int pic2);
#endif