From a6f01b4e4d2c46e46930cacb04f867316957fec7 Mon Sep 17 00:00:00 2001 From: Alex Huddleston Date: Mon, 26 Jun 2017 23:58:19 -0500 Subject: [PATCH] Initial definition of most functions. Debugging page table setup. --- MP3/MP3_Sources/BIOS-bochs-latest | Bin 0 -> 131072 bytes MP3/MP3_Sources/README.TXT | 101 +++++ MP3/MP3_Sources/VGABIOS-lgpl-latest | Bin 0 -> 38400 bytes MP3/MP3_Sources/assert.C | 45 ++ MP3/MP3_Sources/assert.H | 56 +++ MP3/MP3_Sources/bochsrc.bxrc | 48 +++ MP3/MP3_Sources/console.C | 213 +++++++++ MP3/MP3_Sources/console.H | 113 +++++ MP3/MP3_Sources/cont_frame_pool.C | 404 ++++++++++++++++++ MP3/MP3_Sources/cont_frame_pool.H | 132 ++++++ MP3/MP3_Sources/copykernel.sh | 5 + MP3/MP3_Sources/dev_kernel_grub.img | Bin 0 -> 1474560 bytes MP3/MP3_Sources/exceptions.C | 183 ++++++++ MP3/MP3_Sources/exceptions.H | 86 ++++ MP3/MP3_Sources/gdt.C | 124 ++++++ MP3/MP3_Sources/gdt.H | 48 +++ MP3/MP3_Sources/gdt_low.asm | 18 + MP3/MP3_Sources/idt.C | 108 +++++ MP3/MP3_Sources/idt.H | 57 +++ MP3/MP3_Sources/idt_low.asm | 279 ++++++++++++ MP3/MP3_Sources/interrupts.C | 172 ++++++++ MP3/MP3_Sources/interrupts.H | 90 ++++ MP3/MP3_Sources/irq.C | 60 +++ MP3/MP3_Sources/irq.H | 38 ++ MP3/MP3_Sources/irq_low.asm | 136 ++++++ MP3/MP3_Sources/kernel.C | 196 +++++++++ MP3/MP3_Sources/linker.ld | 36 ++ MP3/MP3_Sources/machine.C | 70 +++ MP3/MP3_Sources/machine.H | 123 ++++++ MP3/MP3_Sources/machine_low.H | 31 ++ MP3/MP3_Sources/machine_low.asm | 18 + MP3/MP3_Sources/makefile | 78 ++++ MP3/MP3_Sources/page_table.C | 91 ++++ MP3/MP3_Sources/page_table.H | 91 ++++ MP3/MP3_Sources/paging_low.H | 51 +++ MP3/MP3_Sources/paging_low.asm | 32 ++ MP3/MP3_Sources/simple_keyboard.C | 79 ++++ MP3/MP3_Sources/simple_keyboard.H | 68 +++ MP3/MP3_Sources/simple_timer.C | 100 +++++ MP3/MP3_Sources/simple_timer.H | 70 +++ MP3/MP3_Sources/start.asm | 110 +++++ MP3/MP3_Sources/utils.C | 167 ++++++++ MP3/MP3_Sources/utils.H | 62 +++ MP3/__MACOSX/._MP3_Sources | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._BIOS-bochs-latest | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._README.TXT | Bin 0 -> 239 bytes .../MP3_Sources/._VGABIOS-lgpl-latest | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._assert.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._assert.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._bochsrc.bxrc | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._console.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._console.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._cont_frame_pool.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._cont_frame_pool.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._copykernel.sh | Bin 0 -> 239 bytes .../MP3_Sources/._dev_kernel_grub.img | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._exceptions.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._exceptions.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._gdt.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._gdt.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._gdt_low.asm | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._idt.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._idt.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._idt_low.asm | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._interrupts.C | Bin 0 -> 447 bytes MP3/__MACOSX/MP3_Sources/._interrupts.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._irq.C | Bin 0 -> 447 bytes MP3/__MACOSX/MP3_Sources/._irq.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._irq_low.asm | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._kernel.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._linker.ld | Bin 0 -> 447 bytes MP3/__MACOSX/MP3_Sources/._machine.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._machine.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._machine_low.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._machine_low.asm | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._makefile | Bin 0 -> 447 bytes MP3/__MACOSX/MP3_Sources/._page_table.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._page_table.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._paging_low.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._paging_low.asm | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._simple_keyboard.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._simple_keyboard.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._simple_timer.C | Bin 0 -> 447 bytes MP3/__MACOSX/MP3_Sources/._simple_timer.H | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._start.asm | Bin 0 -> 447 bytes MP3/__MACOSX/MP3_Sources/._utils.C | Bin 0 -> 239 bytes MP3/__MACOSX/MP3_Sources/._utils.H | Bin 0 -> 239 bytes 87 files changed, 3989 insertions(+) create mode 100755 MP3/MP3_Sources/BIOS-bochs-latest create mode 100755 MP3/MP3_Sources/README.TXT create mode 100755 MP3/MP3_Sources/VGABIOS-lgpl-latest create mode 100755 MP3/MP3_Sources/assert.C create mode 100755 MP3/MP3_Sources/assert.H create mode 100755 MP3/MP3_Sources/bochsrc.bxrc create mode 100755 MP3/MP3_Sources/console.C create mode 100755 MP3/MP3_Sources/console.H create mode 100644 MP3/MP3_Sources/cont_frame_pool.C create mode 100755 MP3/MP3_Sources/cont_frame_pool.H create mode 100755 MP3/MP3_Sources/copykernel.sh create mode 100755 MP3/MP3_Sources/dev_kernel_grub.img create mode 100755 MP3/MP3_Sources/exceptions.C create mode 100755 MP3/MP3_Sources/exceptions.H create mode 100755 MP3/MP3_Sources/gdt.C create mode 100755 MP3/MP3_Sources/gdt.H create mode 100755 MP3/MP3_Sources/gdt_low.asm create mode 100755 MP3/MP3_Sources/idt.C create mode 100755 MP3/MP3_Sources/idt.H create mode 100755 MP3/MP3_Sources/idt_low.asm create mode 100755 MP3/MP3_Sources/interrupts.C create mode 100755 MP3/MP3_Sources/interrupts.H create mode 100755 MP3/MP3_Sources/irq.C create mode 100755 MP3/MP3_Sources/irq.H create mode 100755 MP3/MP3_Sources/irq_low.asm create mode 100755 MP3/MP3_Sources/kernel.C create mode 100755 MP3/MP3_Sources/linker.ld create mode 100755 MP3/MP3_Sources/machine.C create mode 100755 MP3/MP3_Sources/machine.H create mode 100755 MP3/MP3_Sources/machine_low.H create mode 100755 MP3/MP3_Sources/machine_low.asm create mode 100755 MP3/MP3_Sources/makefile create mode 100644 MP3/MP3_Sources/page_table.C create mode 100755 MP3/MP3_Sources/page_table.H create mode 100755 MP3/MP3_Sources/paging_low.H create mode 100755 MP3/MP3_Sources/paging_low.asm create mode 100755 MP3/MP3_Sources/simple_keyboard.C create mode 100755 MP3/MP3_Sources/simple_keyboard.H create mode 100755 MP3/MP3_Sources/simple_timer.C create mode 100755 MP3/MP3_Sources/simple_timer.H create mode 100755 MP3/MP3_Sources/start.asm create mode 100755 MP3/MP3_Sources/utils.C create mode 100755 MP3/MP3_Sources/utils.H create mode 100644 MP3/__MACOSX/._MP3_Sources create mode 100644 MP3/__MACOSX/MP3_Sources/._BIOS-bochs-latest create mode 100644 MP3/__MACOSX/MP3_Sources/._README.TXT create mode 100644 MP3/__MACOSX/MP3_Sources/._VGABIOS-lgpl-latest create mode 100644 MP3/__MACOSX/MP3_Sources/._assert.C create mode 100644 MP3/__MACOSX/MP3_Sources/._assert.H create mode 100644 MP3/__MACOSX/MP3_Sources/._bochsrc.bxrc create mode 100644 MP3/__MACOSX/MP3_Sources/._console.C create mode 100644 MP3/__MACOSX/MP3_Sources/._console.H create mode 100644 MP3/__MACOSX/MP3_Sources/._cont_frame_pool.C create mode 100644 MP3/__MACOSX/MP3_Sources/._cont_frame_pool.H create mode 100644 MP3/__MACOSX/MP3_Sources/._copykernel.sh create mode 100644 MP3/__MACOSX/MP3_Sources/._dev_kernel_grub.img create mode 100644 MP3/__MACOSX/MP3_Sources/._exceptions.C create mode 100644 MP3/__MACOSX/MP3_Sources/._exceptions.H create mode 100644 MP3/__MACOSX/MP3_Sources/._gdt.C create mode 100644 MP3/__MACOSX/MP3_Sources/._gdt.H create mode 100644 MP3/__MACOSX/MP3_Sources/._gdt_low.asm create mode 100644 MP3/__MACOSX/MP3_Sources/._idt.C create mode 100644 MP3/__MACOSX/MP3_Sources/._idt.H create mode 100644 MP3/__MACOSX/MP3_Sources/._idt_low.asm create mode 100644 MP3/__MACOSX/MP3_Sources/._interrupts.C create mode 100644 MP3/__MACOSX/MP3_Sources/._interrupts.H create mode 100644 MP3/__MACOSX/MP3_Sources/._irq.C create mode 100644 MP3/__MACOSX/MP3_Sources/._irq.H create mode 100644 MP3/__MACOSX/MP3_Sources/._irq_low.asm create mode 100644 MP3/__MACOSX/MP3_Sources/._kernel.C create mode 100644 MP3/__MACOSX/MP3_Sources/._linker.ld create mode 100644 MP3/__MACOSX/MP3_Sources/._machine.C create mode 100644 MP3/__MACOSX/MP3_Sources/._machine.H create mode 100644 MP3/__MACOSX/MP3_Sources/._machine_low.H create mode 100644 MP3/__MACOSX/MP3_Sources/._machine_low.asm create mode 100644 MP3/__MACOSX/MP3_Sources/._makefile create mode 100644 MP3/__MACOSX/MP3_Sources/._page_table.C create mode 100644 MP3/__MACOSX/MP3_Sources/._page_table.H create mode 100644 MP3/__MACOSX/MP3_Sources/._paging_low.H create mode 100644 MP3/__MACOSX/MP3_Sources/._paging_low.asm create mode 100644 MP3/__MACOSX/MP3_Sources/._simple_keyboard.C create mode 100644 MP3/__MACOSX/MP3_Sources/._simple_keyboard.H create mode 100644 MP3/__MACOSX/MP3_Sources/._simple_timer.C create mode 100644 MP3/__MACOSX/MP3_Sources/._simple_timer.H create mode 100644 MP3/__MACOSX/MP3_Sources/._start.asm create mode 100644 MP3/__MACOSX/MP3_Sources/._utils.C create mode 100644 MP3/__MACOSX/MP3_Sources/._utils.H diff --git a/MP3/MP3_Sources/BIOS-bochs-latest b/MP3/MP3_Sources/BIOS-bochs-latest new file mode 100755 index 0000000000000000000000000000000000000000..2cb4488a03c2a293569e147b09de2e2ae108fee4 GIT binary patch literal 131072 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

M$_)7 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 Y92H(6x>>(9bkByy4dUk?6XfmtKgu1I8~^|S literal 0 HcmV?d00001 diff --git a/MP3/MP3_Sources/assert.C b/MP3/MP3_Sources/assert.C new file mode 100755 index 0000000..e85ae1d --- /dev/null +++ b/MP3/MP3_Sources/assert.C @@ -0,0 +1,45 @@ +/* + File: assert.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + + Date : 05/01/23 + + Implementation of the assert() function. + +*/ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "assert.H" + +#include "utils.H" +#include "console.H" + +/*--------------------------------------------------------------------------*/ +/* _assert() FUNCTION: gets called when assert() macro fails. */ +/*--------------------------------------------------------------------------*/ + +void _assert (const char* _file, const int _line, const char* _message ) { + /* Prints current file, line number, and failed assertion. */ + char temp[15]; + Console::puts("Assertion failed at file: "); + Console::puts(_file); + Console::puts(" line: "); + int2str(_line, temp); + Console::puts(temp); + Console::puts(" assertion: "); + Console::puts(_message); + Console::puts("\n"); + abort(); +}/* end _assert */ diff --git a/MP3/MP3_Sources/assert.H b/MP3/MP3_Sources/assert.H new file mode 100755 index 0000000..33c7a16 --- /dev/null +++ b/MP3/MP3_Sources/assert.H @@ -0,0 +1,56 @@ +/* + File: assert.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + + Date : 05/01/23 + + Header file for the "assert" macro. + + +*/ + +#ifndef __assert_H__ +#define __assert_H__ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "utils.H" + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* CONSTANTS */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* "ASSERT" MACRO */ +/*--------------------------------------------------------------------------*/ + +/* NOTE: The "assert" macros can be turned off by giving the -DNDEBUG + argument when compiling. */ + +#ifdef assert +# undef assert +#endif + +void _assert ( const char* _file, const int _line, const char* _message ); + +#ifdef NDEBUG +# define assert( m ) ( ( void ) 0 ) +#else +# define assert( m ) \ + if ( !(m) ) _assert( __FILE__, __LINE__, #m ); +#endif + +#endif diff --git a/MP3/MP3_Sources/bochsrc.bxrc b/MP3/MP3_Sources/bochsrc.bxrc new file mode 100755 index 0000000..310979c --- /dev/null +++ b/MP3/MP3_Sources/bochsrc.bxrc @@ -0,0 +1,48 @@ +############################################################### +# bochsrc.txt file for DLX Linux disk image. +############################################################### + +# how much memory the emulated machine will have +megs: 32 + +# filename of ROM images +romimage: file=BIOS-bochs-latest +vgaromimage: file=VGABIOS-lgpl-latest + +# what disk images will be used +floppya: 1_44=dev_kernel_grub.img, status=inserted +#floppyb: 1_44=floppyb.img, status=inserted + +# hard disk +#ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +#ata0-master: type=disk, path="c.img", cylinders=306, heads=4, spt=17 +# choose the boot disk. +boot: floppy + +# default config interface is textconfig. +#config_interface: textconfig +#config_interface: wx + +#display_library: x +# other choices: win32 sdl wx carbon amigaos beos macintosh nogui rfb term svga + +# where do we send log messages? +log: bochsout.txt + +# disable the mouse +mouse: enabled=0 + +# enable key mapping, using US layout as default. +# +# NOTE: In Bochs 1.4, keyboard mapping is only 100% implemented on X windows. +# However, the key mapping tables are used in the paste function, so +# in the DLX Linux example I'm enabling keyboard_mapping so that paste +# will work. Cut&Paste is currently implemented on win32 and X windows only. + +#keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-us.map +#keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-fr.map +#keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-de.map +#keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-es.map + + +clock: sync=realtime, time0=946681200 # Sat Jan 1 00:00:00 2000 \ No newline at end of file diff --git a/MP3/MP3_Sources/console.C b/MP3/MP3_Sources/console.C new file mode 100755 index 0000000..2fc0899 --- /dev/null +++ b/MP3/MP3_Sources/console.C @@ -0,0 +1,213 @@ +/* + File: Console.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/02/2009 + +*/ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +#define CONSOLE_START_ADDRESS (unsigned short *)0xB8000 + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "console.H" + +#include "utils.H" +#include "machine.H" + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* CONSTANTS */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* FORWARDS */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* METHODS FOR CLASS C o n s o l e */ +/*--------------------------------------------------------------------------*/ + +/* -- GLOBAL VARIABLES -- */ + + int Console::attrib; /* background and foreground color */ + int Console::csr_x; /* position of cursor */ + int Console::csr_y; + unsigned short * Console::textmemptr; /* text pointer */ + +/* -- CONSTRUCTOR -- */ + +void Console::init(unsigned char _fore_color, + unsigned char _back_color) { + set_TextColor(_fore_color, _back_color); + csr_x = 0; + csr_y = 0; + textmemptr = CONSOLE_START_ADDRESS; + cls(); +} + + +void Console::scroll() { + + /* A blank is defined as a space... we need to give it + * backcolor too */ + unsigned blank = 0x20 | (attrib << 8); + + /* Row 25 is the end, this means we need to scroll up */ + if(csr_y >= 25) + { + /* Move the current text chunk that makes up the screen + * back in the buffer by a line */ + unsigned temp = csr_y - 25 + 1; + memcpy ((char*)textmemptr, (char*)(textmemptr + temp * 80), (25 - temp) * 80 * 2); + + /* Finally, we set the chunk of memory that occupies + * the last line of text to our 'blank' character */ + memsetw (textmemptr + (25 - temp) * 80, blank, 80); + csr_y = 25 - 1; + } +} + + +void Console::move_cursor() { + + /* The equation for finding the index in a linear + * chunk of memory can be represented by: + * Index = [(y * width) + x] */ + unsigned temp = csr_y * 80 + csr_x; + + /* This sends a command to indicies 14 and 15 in the + * Console Control Register of the VGA controller. These + * are the high and low bytes of the index that show + * where the hardware cursor is to be 'blinking'. To + * learn more, you should look up some VGA specific + * programming documents. A great start to graphics: + * http://www.brackeen.com/home/vga */ + Machine::outportb(0x3D4, (char)14); + //outportb(0x3D5, temp >> 8); + Machine::outportb(0x3D4, 15); + //outportb(0x3D5, (char)temp); +} + +/* Clear the screen */ +void Console::cls() { + + /* Again, we need the 'short' that will be used to + * represent a space with color */ + unsigned blank = 0x20 | (attrib << 8); + + /* Sets the entire screen to spaces in our current + * color */ + for(int i = 0; i < 25; i++) + memsetw (textmemptr + i * 80, blank, 80); + + /* Update out virtual cursor, and then move the + * hardware cursor */ + csr_x = 0; + csr_y = 0; + move_cursor(); +} + +/* Puts a single character on the screen */ +void Console::putch(const char _c){ + + + /* Handle a backspace, by moving the cursor back one space */ + if(_c == 0x08) + { + if(csr_x != 0) csr_x--; + } + /* Handles a tab by incrementing the cursor's x, but only + * to a point that will make it divisible by 8 */ + else if(_c == 0x09) + { + csr_x = (csr_x + 8) & ~(8 - 1); + } + /* Handles a 'Carriage Return', which simply brings the + * cursor back to the margin */ + else if(_c == '\r') + { + csr_x = 0; + } + /* We handle our newlines the way DOS and the BIOS do: we + * treat it as if a 'CR' was also there, so we bring the + * cursor to the margin and we increment the 'y' value */ + else if(_c == '\n') + { + csr_x = 0; + csr_y++; + } + /* Any character greater than and including a space, is a + * printable character. The equation for finding the index + * in a linear chunk of memory can be represented by: + * Index = [(y * width) + x] */ + else if(_c >= ' ') + { + unsigned short * where = textmemptr + (csr_y * 80 + csr_x); + *where = _c | (attrib << 8); /* Character AND attributes: color */ + csr_x++; + } + + /* If the cursor has reached the edge of the screen's width, we + * insert a new line in there */ + if(csr_x >= 80) + { + csr_x = 0; + csr_y++; + } + + /* Scroll the screen if needed, and finally move the cursor */ + scroll(); + move_cursor(); +} + +/* Uses the above routine to output a string... */ +void Console::puts(const char * _s) { + + for (int i = 0; i < strlen(_s); i++) { + putch(_s[i]); + } +} + +void Console::puti(const int _n) { + char foostr[15]; + + int2str(_n, foostr); + puts(foostr); +} + +void Console::putui(const unsigned int _n) { + char foostr[15]; + + uint2str(_n, foostr); + putch('<'); + puts(foostr); + putch('>'); +} + + +/* -- COLOR CONTROL -- */ +void Console::set_TextColor(const unsigned char _forecolor, + const unsigned char _backcolor) { + /* Top 4 bytes are the background, bottom 4 bytes + * are the foreground color */ + attrib = (_backcolor << 4) | (_forecolor & 0x0F); +} + diff --git a/MP3/MP3_Sources/console.H b/MP3/MP3_Sources/console.H new file mode 100755 index 0000000..aa24fda --- /dev/null +++ b/MP3/MP3_Sources/console.H @@ -0,0 +1,113 @@ +/* + File: Console.H + + Author : R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/02/12 + + The class Console encapsulates the output operations ot the console + screen. Since the console is initialized at the very beginning of the + boot-up of the operating system, when no memory management is available + yet, all functions and storage for the console are static. + + The console is initialized with an "init" function instead of a + constructor. (We don't want to deal with constructors that are called + before the "main()" function.) + + By making all functions static, we can access them across all object + files without having to declare a global Console object or pass pointers + to a locally declared object. + +*/ + +#ifndef _Console_H_ // include file only once +#define _Console_H_ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +/* -- (none -- */ + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + +typedef enum { + BLACK = 0, + BLUE = 1, + GREEN = 2, + CYAN = 3, + RED = 4, + MAGENTA = 5, + BROWN = 6, + LIGHT_GREY = 7, + DARK_GREY = 8, + LIGHT_BLUE = 9, + LIGHT_GREEN = 10, + LIGHT_CYAN = 11, + LIGHT_RED = 12, + LIGHT_MAGENTA = 13, + LIGHT_BROWN = 14, + WHITE = 15 +} COLOR_CODE; + + +/*--------------------------------------------------------------------------*/ +/* FORWARDS */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* CLASS C o n s o l e */ +/*--------------------------------------------------------------------------*/ + +class Console { +private: + static int attrib; /* background and foreground color */ + static int csr_x; /* position of cursor */ + static int csr_y; + static unsigned short * textmemptr; /* text pointer */ +public: + + /* -- INITIALIZER (we have no constructor, there is no memory mgmt yet.) */ + static void init(unsigned char _fore_color = WHITE, + unsigned char _back_color = BLACK); + + static void scroll(); + + static void move_cursor(); + /* Update the hardware cursor. */ + + static void cls(); + /* Clear the screen. */ + + static void putch(const char _c); + /* Put a single character on the screen. */ + + static void puts(const char * _s); + /* Display a NULL-terminated string on the screen.*/ + + static void puti(const int _i); + /* Display a integer on the screen.*/ + + static void putui(const unsigned int _u); + /* Display a unsigned integer on the screen.*/ + + static void set_TextColor(unsigned char _fore_color, unsigned char _back_color); + /* Set the color of the foreground and background. */ + +}; + + +#endif + + diff --git a/MP3/MP3_Sources/cont_frame_pool.C b/MP3/MP3_Sources/cont_frame_pool.C new file mode 100644 index 0000000..3c1af89 --- /dev/null +++ b/MP3/MP3_Sources/cont_frame_pool.C @@ -0,0 +1,404 @@ +/* + File: ContFramePool.C + + Author: + Date : + + */ + +/*--------------------------------------------------------------------------*/ +/* + POSSIBLE IMPLEMENTATION + ----------------------- + + The class SimpleFramePool in file "simple_frame_pool.H/C" describes an + incomplete vanilla implementation of a frame pool that allocates + *single* frames at a time. Because it does allocate one frame at a time, + it does not guarantee that a sequence of frames is allocated contiguously. + This can cause problems. + + The class ContFramePool has the ability to allocate either single frames, + or sequences of contiguous frames. This affects how we manage the + free frames. In SimpleFramePool it is sufficient to maintain the free + frames. + In ContFramePool we need to maintain free *sequences* of frames. + + This can be done in many ways, ranging from extensions to bitmaps to + free-lists of frames etc. + + IMPLEMENTATION: + + One simple way to manage sequences of free frames is to add a minor + extension to the bitmap idea of SimpleFramePool: Instead of maintaining + whether a frame is FREE or ALLOCATED, which requires one bit per frame, + we maintain whether the frame is FREE, or ALLOCATED, or HEAD-OF-SEQUENCE. + The meaning of FREE is the same as in SimpleFramePool. + If a frame is marked as HEAD-OF-SEQUENCE, this means that it is allocated + and that it is the first such frame in a sequence of frames. Allocated + frames that are not first in a sequence are marked as ALLOCATED. + + NOTE: If we use this scheme to allocate only single frames, then all + frames are marked as either FREE or HEAD-OF-SEQUENCE. + + NOTE: In SimpleFramePool we needed only one bit to store the state of + each frame. Now we need two bits. In a first implementation you can choose + to use one char per frame. This will allow you to check for a given status + without having to do bit manipulations. Once you get this to work, + revisit the implementation and change it to using two bits. You will get + an efficiency penalty if you use one char (i.e., 8 bits) per frame when + two bits do the trick. + + DETAILED IMPLEMENTATION: + + How can we use the HEAD-OF-SEQUENCE state to implement a contiguous + allocator? Let's look a the individual functions: + + Constructor: Initialize all frames to FREE, except for any frames that you + need for the management of the frame pool, if any. + + get_frames(_n_frames): Traverse the "bitmap" of states and look for a + sequence of at least _n_frames entries that are FREE. If you find one, + mark the first one as HEAD-OF-SEQUENCE and the remaining _n_frames-1 as + ALLOCATED. + + release_frames(_first_frame_no): Check whether the first frame is marked as + HEAD-OF-SEQUENCE. If not, something went wrong. If it is, mark it as FREE. + Traverse the subsequent frames until you reach one that is FREE or + HEAD-OF-SEQUENCE. Until then, mark the frames that you traverse as FREE. + + mark_inaccessible(_base_frame_no, _n_frames): This is no different than + get_frames, without having to search for the free sequence. You tell the + allocator exactly which frame to mark as HEAD-OF-SEQUENCE and how many + frames after that to mark as ALLOCATED. + + needed_info_frames(_n_frames): This depends on how many bits you need + to store the state of each frame. If you use a char to represent the state + of a frame, then you need one info frame for each FRAME_SIZE frames. + + A WORD ABOUT RELEASE_FRAMES(): + + When we releae a frame, we only know its frame number. At the time + of a frame's release, we don't know necessarily which pool it came + from. Therefore, the function "release_frame" is static, i.e., + not associated with a particular frame pool. + + This problem is related to the lack of a so-called "placement delete" in + C++. For a discussion of this see Stroustrup's FAQ: + http://www.stroustrup.com/bs_faq2.html#placement-delete + + */ +/*--------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "cont_frame_pool.H" +#include "console.H" +#include "utils.H" +#include "assert.H" + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* CONSTANTS */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* FORWARDS */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* METHODS FOR CLASS C o n t F r a m e P o o l */ +/*--------------------------------------------------------------------------*/ + +ContFramePool* ContFramePool::pools = (ContFramePool *) FRAME_SIZE; // List of frame pools, managed by the class +unsigned int ContFramePool::nPools = 0; // Number of pools being managed + +ContFramePool::ContFramePool(unsigned long _base_frame_no, + unsigned long _n_frames, + unsigned long _info_frame_no, + unsigned long _n_info_frames) +{ + // Bitmap must fit in a single frame! + // NOTE: In theory, we don't need to make the bitmap any larger, + // since as stated in the instructions it is already big enough to + // hold for 128MB of memory with one bit per frame, so should still + // be enough for 64MB of memory with 2 bits per frame. + // Assertion changed to match max size of frames allowed. + assert(_n_frames <= FRAME_SIZE * 4); + + base_frame_no = _base_frame_no; + nframes = _n_frames; + nFreeFrames = _n_frames; + info_frame_no = _info_frame_no; + n_info_frames = _n_info_frames; + + // If _info_frame_no is zero then we keep management info in the first + // frame(s), else we use the provided frame(s) to keep management info + // NOTE: bitmap needs to be allocated with n_info_frames if specified. + if(info_frame_no == 0) + { + bitmap = (unsigned char *) (base_frame_no * FRAME_SIZE); + } + else + { + bitmap = (unsigned char *) (info_frame_no * FRAME_SIZE * n_info_frames); + } + + // Number of frames must "fill" the bitmap! + assert ((nframes % 8 ) == 0); + + + // Everything ok. Proceed to mark all bits in the bitmap + // NOTE: changed to reflect that I need 2 bits per frame now + for(int i=0; i*4 < _n_frames; i++) + { + bitmap[i] = 0xFF; + } + + // Mark the first frame as being used if it is being used + // NOTE: need to mark multiple frames if needed. + if(info_frame_no == 0) + { + bitmap[0] = 0x3F; + nFreeFrames--; + } + else + { + unsigned int i = info_frame_no / 4; + unsigned int r = info_frame_no % 4; + unsigned char mask = 0x80; + mask = mask >> r*2; + + unsigned int c = 0; + while(c < n_info_frames) + { + bitmap[i] = bitmap[i] ^ mask; + bitmap[i] = bitmap[i] ^ (mask >> 1); + if(mask == 0x02) + { + i++; + mask = 0x80; + } + c++; + nFreeFrames--; + } + + } + + pools[nPools] = *this; + nPools += 1; + + Console::puts("Frame Pool initialized\n"); +} + +unsigned long ContFramePool::get_frames(unsigned int _n_frames) +{ + // Are there enough frames left to allocate? + assert(nFreeFrames > _n_frames); + + // Find a frame that is not being used and return its frame index. + // Mark that frame as being used in the bitmap. + // NOTE: Must be updated to find a sequence of contiguous frames + // that are not being used and return the index of the head. + unsigned int frame_no = base_frame_no; + + // i is being used as the frame_no / 4 + // j is frame_no % 4 + // together, they will give the actual frame_no. + // c is used as a counter to count a squence of free frames. + unsigned int i = 0; + unsigned int j = 0; + unsigned int c = 0; + + while (true) + { + unsigned char mask = 0x80 >> (j*2); + // check every 2 bits for a free frame in the bitmap + while((mask & bitmap[i]) == 0 || ((mask >> 1) & bitmap[i]) == 0) + { + if(mask != 0x02) + { + j++; + mask = mask >> 2; + } + else + { + i++; + j = 0; + mask = 0x80; + } + } + // if frame is found, start checking for sequence + unsigned int temp = i; + c++; + while(c < _n_frames) + { + if(mask != 0x02) + { + mask = mask >> 2; + } + else + { + temp++; + mask = 0x80; + } + if((mask & bitmap[temp]) != 0 && ((mask >> 1) & bitmap[temp]) != 0) + { + c++; + } + else + { + c = 0; + break; + } + } + if(c == _n_frames) + { + nFreeFrames -= _n_frames; + break; + } + } + + frame_no += i*4 + j; + + // Update bitmap + // First: clear most significant bit to mark head of sequence. + bitmap[i] = bitmap[i] ^ (0x80 >> (j*2)); + // Second: clear both bits for all remaining frames in the sequence. + c = 1; + unsigned char mask = 0x80 >> j*2; + unsigned int temp = i; + while(c < _n_frames) + { + if(mask != 0x02) + { + mask = mask >> 2; + } + else + { + temp++; + mask = 0x80; + } + + bitmap[temp] = bitmap[temp] ^ mask; + bitmap[temp] = bitmap[temp] ^ (mask >> 1); + c++; + } + + return (frame_no); +} + +void ContFramePool::mark_inaccessible(unsigned long _base_frame_no, + unsigned long _n_frames) +{ + // Mark all frames in the range as being used. + int i ; + for(i = _base_frame_no; i < _base_frame_no + _n_frames; i++){ + mark_inaccessible(i); + } + nFreeFrames -= _n_frames; +} + +void ContFramePool::mark_inaccessible(unsigned long _frame_no) +{ + // Let's first do a range check. + assert ((_frame_no >= base_frame_no) && (_frame_no < base_frame_no + nframes)); + + unsigned int bitmap_index = (_frame_no - base_frame_no) / 4; + unsigned char mask = 0x80 >> ((_frame_no - base_frame_no) % 4) * 2; + + // Is the frame being used already? + assert(((bitmap[bitmap_index] & mask) != 0) && (bitmap[bitmap_index] & (mask >> 1)) != 0); + + // Update bitmap + bitmap[bitmap_index] ^= mask; + bitmap[bitmap_index] ^= mask >> 1; + nFreeFrames--; +} + +void ContFramePool::release_frames(unsigned long _frame_no) +{ + unsigned int i = 0; + while(i < nPools) + { + if(_frame_no <= pools[i].base_frame_no || _frame_no > (pools[i].base_frame_no + pools[i].nframes)) + { + i++; + } + else + { + pools[i].release_frames_here(_frame_no); + return; + } + } +} + +void ContFramePool::release_frames_here(unsigned long _first_frame_no) +{ + unsigned char * bitmap = this->bitmap; + + unsigned int bitmap_index = (_first_frame_no - base_frame_no) / 4; + unsigned char mask = 0x80 >> ((_first_frame_no - base_frame_no) % 4) * 2; + + if(!((bitmap[bitmap_index] & mask) == 0 && (bitmap[bitmap_index] & (mask >> 1)) != 0)) + { + if((bitmap[bitmap_index] & mask) != 0 && (bitmap[bitmap_index] & (mask >> 1)) != 0) + { + Console::puts("Error, Frame being released is not being used\n"); + assert(false); + } + Console::puts("Error, Frame being released is not head of sequence\n"); + assert(false); + } + + bitmap[bitmap_index] ^= mask; + nFreeFrames++; + + if(mask != 0x02) + { + mask = mask >> 2; + } + else + { + mask = 0x80; + bitmap_index++; + } + + while(bitmap[bitmap_index] & mask == 0 && (bitmap[bitmap_index] & (mask >> 1)) == 0) + { + bitmap[bitmap_index] ^= mask; + bitmap[bitmap_index] ^= (mask >> 1); + if(mask != 0x02) + { + mask = mask >> 2; + } + else + { + mask = 0x80; + bitmap_index++; + } + nFreeFrames++; + } +} + +unsigned long ContFramePool::needed_info_frames(unsigned long _n_frames) +{ + return (_n_frames / (FRAME_SIZE * 4)) + (_n_frames % (FRAME_SIZE * 4) > 0 ? 1 : 0); +} diff --git a/MP3/MP3_Sources/cont_frame_pool.H b/MP3/MP3_Sources/cont_frame_pool.H new file mode 100755 index 0000000..13c7a07 --- /dev/null +++ b/MP3/MP3_Sources/cont_frame_pool.H @@ -0,0 +1,132 @@ +/* + File: cont_frame_pool.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 17/02/04 + + Description: Management of the CONTIGUOUS Free-Frame Pool. + + As opposed to a non-contiguous free-frame pool, here we can allocate + a sequence of CONTIGUOUS frames. + + */ + +#ifndef _CONT_FRAME_POOL_H_ // include file only once +#define _CONT_FRAME_POOL_H_ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "machine.H" + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* C o n t F r a m e P o o l */ +/*--------------------------------------------------------------------------*/ + +class ContFramePool { + +private: + /* -- DEFINE YOUR CONT FRAME POOL DATA STRUCTURE(s) HERE. */ + + unsigned char * bitmap; // Remember the bitmap here needs 2 bits per frame + unsigned int nFreeFrames; // + unsigned long base_frame_no; // Where does the frame pool start in phys mem? + unsigned long nframes; // Size of the frame pool + unsigned long info_frame_no; // Where do we store the management information? + unsigned long n_info_frames; // Number of frames needed to store management info + static ContFramePool* pools; // List of frame pools, managed by the class + static unsigned int nPools; // Number of pools being managed + + void mark_inaccessible(unsigned long _frame_no); // Should be a frame marked as + // a head, otherwise fails + void release_frames_here(unsigned long _frame_no); // non-static member function + +public: + + // The frame size is the same as the page size, duh... + static const unsigned int FRAME_SIZE = Machine::PAGE_SIZE; + + ContFramePool(unsigned long _base_frame_no, + unsigned long _n_frames, + unsigned long _info_frame_no, + unsigned long _n_info_frames); + /* + Initializes the data structures needed for the management of this + frame pool. + _base_frame_no: Number of first frame managed by this frame pool. + _n_frames: Size, in frames, of this frame pool. + EXAMPLE: If _base_frame_no is 16 and _n_frames is 4, this frame pool manages + physical frames numbered 16, 17, 18 and 19. + _info_frame_no: Number of the first frame that should be used to store the + management information for the frame pool. + NOTE: If _info_frame_no is 0, the frame pool is free to + choose any frames from the pool to store management information. + _n_info_frames: If _info_frame_no is 0, this argument specifies the + number of consecutive frames needed to store the management information + for the frame pool. + EXAMPLE: If _info_frame_no is 699 and _n_info_frames is 3, + then Frames 699, 700, and 701 are used to store the management information + for the frame pool. + NOTE: This function must be called before the paging system + is initialized. + */ + + unsigned long get_frames(unsigned int _n_frames); + /* + Allocates a number of contiguous frames from the frame pool. + _n_frames: Size of contiguous physical memory to allocate, + in number of frames. + If successful, returns the frame number of the first frame. + If fails, returns 0. + */ + + void mark_inaccessible(unsigned long _base_frame_no, + unsigned long _n_frames); + /* + Marks a contiguous area of physical memory, i.e., a contiguous + sequence of frames, as inaccessible. + _base_frame_no: Number of first frame to mark as inaccessible. + _n_frames: Number of contiguous frames to mark as inaccessible. + */ + + static void release_frames(unsigned long _frame_no); + /* + Releases a previously allocated contiguous sequence of frames + back to its frame pool. + The frame sequence is identified by the number of the first frame. + NOTE: This function is static because there may be more than one frame pool + defined in the system, and it is unclear which one this frame belongs to. + This function must first identify the correct frame pool and then call the frame + pool's release_frame function. + */ + + static unsigned long needed_info_frames(unsigned long _n_frames); + /* + Returns the number of frames needed to manage a frame pool of size _n_frames. + The number returned here depends on the implementation of the frame pool and + on the frame size. + EXAMPLE: For FRAME_SIZE = 4096 and a bitmap with a single bit per frame + (not appropriate for contiguous allocation) one would need one frame to manage a + frame pool with up to 8 * 4096 = 32k frames = 128MB of memory! + This function would therefore return the following value: + _n_frames / 32k + (_n_frames % 32k > 0 ? 1 : 0) (always round up!) + Other implementations need a different number of info frames. + The exact number is computed in this function.. + */ +}; +#endif diff --git a/MP3/MP3_Sources/copykernel.sh b/MP3/MP3_Sources/copykernel.sh new file mode 100755 index 0000000..afd49c3 --- /dev/null +++ b/MP3/MP3_Sources/copykernel.sh @@ -0,0 +1,5 @@ +# Replace "/mnt/floppy" with the whatever directory is appropriate. +sudo mount -o loop dev_kernel_grub.img /mnt/floppy +sudo cp kernel.bin /mnt/floppy +sleep 1s +sudo umount /mnt/floppy diff --git a/MP3/MP3_Sources/dev_kernel_grub.img b/MP3/MP3_Sources/dev_kernel_grub.img new file mode 100755 index 0000000000000000000000000000000000000000..ed7450cccd1b6cdd511303dfc6efa790b8ff03dc GIT binary patch literal 1474560 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 z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNCf_g>)t0HGf> AiU0rr literal 0 HcmV?d00001 diff --git a/MP3/MP3_Sources/exceptions.C b/MP3/MP3_Sources/exceptions.C new file mode 100755 index 0000000..6192cb2 --- /dev/null +++ b/MP3/MP3_Sources/exceptions.C @@ -0,0 +1,183 @@ +/* + File: exceptions.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 12/09/05 + +*/ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "assert.H" +#include "utils.H" +#include "console.H" +#include "idt.H" +#include "exceptions.H" + +/*--------------------------------------------------------------------------*/ +/* EXTERNS */ +/*--------------------------------------------------------------------------*/ + +/* The low-level functions (defined in file 'IDT::low.s') that handle the + 32 Intel-defined CPU exceptions. + These functions are actually merely stubs that put the error code and + the exception code on the stack and then call a low-level function, which + in turn calls the exception dispatcher (defined in 'exceptions.H'). + Yes, there are more efficient ways to handle exceptions, but they require more + code replication. +*/ +extern "C" void isr0(); +extern "C" void isr1(); +extern "C" void isr2(); +extern "C" void isr3(); +extern "C" void isr4(); +extern "C" void isr5(); +extern "C" void isr6(); +extern "C" void isr7(); +extern "C" void isr8(); +extern "C" void isr9(); +extern "C" void isr10(); +extern "C" void isr11(); +extern "C" void isr12(); +extern "C" void isr13(); +extern "C" void isr14(); +extern "C" void isr15(); +extern "C" void isr16(); +extern "C" void isr17(); +extern "C" void isr18(); +extern "C" void isr19(); +extern "C" void isr20(); +extern "C" void isr21(); +extern "C" void isr22(); +extern "C" void isr23(); +extern "C" void isr24(); +extern "C" void isr25(); +extern "C" void isr26(); +extern "C" void isr27(); +extern "C" void isr28(); +extern "C" void isr29(); +extern "C" void isr30(); +extern "C" void isr31(); + +extern "C" void lowlevel_dispatch_exception(REGS * _r) { + ExceptionHandler::dispatch_exception(_r); +} + +/*--------------------------------------------------------------------------*/ +/* STATIC VARIABLES */ +/*--------------------------------------------------------------------------*/ + +ExceptionHandler * ExceptionHandler::handler_table[ExceptionHandler::EXCEPTION_TABLE_SIZE]; + +/*--------------------------------------------------------------------------*/ +/* EXPORTED EXCEPTION DISPATCHER FUNCTIONS */ +/*--------------------------------------------------------------------------*/ + +void ExceptionHandler::init_dispatcher() { + + /* -- INITIALIZE LOW-LEVEL EXCEPTION HANDLERS */ + /* Add any new ISRs to the IDT here using IDT::set_gate */ + IDT::set_gate( 0, (unsigned) isr0, 0x08, 0x8E); + IDT::set_gate( 1, (unsigned) isr1, 0x08, 0x8E); + IDT::set_gate( 2, (unsigned) isr2, 0x08, 0x8E); + IDT::set_gate( 3, (unsigned) isr3, 0x08, 0x8E); + IDT::set_gate( 4, (unsigned) isr4, 0x08, 0x8E); + IDT::set_gate( 5, (unsigned) isr5, 0x08, 0x8E); + IDT::set_gate( 6, (unsigned) isr6, 0x08, 0x8E); + IDT::set_gate( 7, (unsigned) isr7, 0x08, 0x8E); + + IDT::set_gate( 8, (unsigned) isr8, 0x08, 0x8E); + IDT::set_gate( 9, (unsigned) isr9, 0x08, 0x8E); + IDT::set_gate(10, (unsigned)isr10, 0x08, 0x8E); + IDT::set_gate(11, (unsigned)isr11, 0x08, 0x8E); + IDT::set_gate(12, (unsigned)isr12, 0x08, 0x8E); + IDT::set_gate(13, (unsigned)isr13, 0x08, 0x8E); + IDT::set_gate(14, (unsigned)isr14, 0x08, 0x8E); + IDT::set_gate(15, (unsigned)isr15, 0x08, 0x8E); + + IDT::set_gate(16, (unsigned)isr16, 0x08, 0x8E); + IDT::set_gate(17, (unsigned)isr17, 0x08, 0x8E); + IDT::set_gate(18, (unsigned)isr18, 0x08, 0x8E); + IDT::set_gate(19, (unsigned)isr19, 0x08, 0x8E); + IDT::set_gate(20, (unsigned)isr20, 0x08, 0x8E); + IDT::set_gate(21, (unsigned)isr21, 0x08, 0x8E); + IDT::set_gate(22, (unsigned)isr22, 0x08, 0x8E); + IDT::set_gate(23, (unsigned)isr23, 0x08, 0x8E); + + IDT::set_gate(24, (unsigned)isr24, 0x08, 0x8E); + IDT::set_gate(25, (unsigned)isr25, 0x08, 0x8E); + IDT::set_gate(26, (unsigned)isr26, 0x08, 0x8E); + IDT::set_gate(27, (unsigned)isr27, 0x08, 0x8E); + IDT::set_gate(28, (unsigned)isr28, 0x08, 0x8E); + IDT::set_gate(29, (unsigned)isr29, 0x08, 0x8E); + IDT::set_gate(30, (unsigned)isr30, 0x08, 0x8E); + IDT::set_gate(31, (unsigned)isr31, 0x08, 0x8E); + + /* -- INITIALIZE THE HIGH-LEVEL EXCEPTION HANDLER */ + int i; + for(i = 0; i < EXCEPTION_TABLE_SIZE; i++) { + handler_table[i] = NULL; + } +} + +void ExceptionHandler::dispatch_exception(REGS * _r) { + + /* -- EXCEPTION NUMBER */ + unsigned int exc_no = _r->int_no; + + Console::puts("EXCEPTION DISPATCHER: exc_no = "); + Console::putui(exc_no); + Console::puts("\n"); + + assert((exc_no >= 0) && (exc_no < EXCEPTION_TABLE_SIZE)); + + /* -- HAS A HANDLER BEEN REGISTERED FOR THIS EXCEPTION NO? */ + ExceptionHandler * handler = handler_table[exc_no]; + + if (!handler) { + /* --- NO HANDLER HAS BEEN REGISTERED. SIMPLY RETURN AN ERROR. */ + Console::puts("NO DEFAULT EXCEPTION HANDLER REGISTERED\n"); + abort(); + } + else { + /* -- HANDLE THE EXCEPTION OR INTERRUPT */ + handler->handle_exception(_r); + } + +} + +void ExceptionHandler::register_handler(unsigned int _isr_code, + ExceptionHandler * _handler) { + + assert(_isr_code >= 0 && _isr_code < EXCEPTION_TABLE_SIZE); + + handler_table[_isr_code] = _handler; + + Console::puts("Installed exception handler at ISR "); + Console::putui(_isr_code); + Console::puts("\n"); + +} + +void ExceptionHandler::deregister_handler(unsigned int _isr_code) { + assert(_isr_code >= 0 && _isr_code < EXCEPTION_TABLE_SIZE); + + handler_table[_isr_code] = NULL; + + Console::puts("UNINSTALLED exception handler at ISR "); + Console::putui(_isr_code); + Console::puts("\n"); + +} + + diff --git a/MP3/MP3_Sources/exceptions.H b/MP3/MP3_Sources/exceptions.H new file mode 100755 index 0000000..88a683b --- /dev/null +++ b/MP3/MP3_Sources/exceptions.H @@ -0,0 +1,86 @@ +/* + File: exceptions.h + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 12/09/05 + + Description: High-level exception handling. + + CPU exceptions are caught by low-level exception and interrupt + handler stubs, which all eventually cause the high-level + exception dispatcher to be called (see 'dispatch_exception() below). + + The dispatcher then looks up the appropriate exception handler + for the given exception, and calls it. + Specific exception handlers are installed by registering an exception handler + object of a class appropriately derived from class 'ExceptionHandler'. The + functionality of the exception handler is then implemented in function + 'handle_exception(REGS * _regs)'. + + +*/ + +#ifndef _exceptions_H_ // include file only once +#define _exceptions_H_ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "assert.H" +#include "machine.H" + +/*--------------------------------------------------------------------------*/ +/* E x c e p t i o n H a n d l e r */ +/*--------------------------------------------------------------------------*/ + +class ExceptionHandler { + + private: + + /* The Exception Handler Table */ + const static int EXCEPTION_TABLE_SIZE = 32; + static ExceptionHandler * handler_table[EXCEPTION_TABLE_SIZE]; + + public: + + /* -- POPULATE DISPATCHER TABLE */ + + static void register_handler(unsigned int _isr_code, + ExceptionHandler * _handler); + /* This function allows to install an exception handler for the given + exception code. The handler is a function pointer defined above. + Interrupt handlers are installed as exception handlers as well. + The 'register_interrupt' function uses irq2isr to map the IRQ + number to the code. */ + + static void deregister_handler(unsigned int _isr_code); + + /* -- DISPATCHER */ + static void init_dispatcher(); + /* This function is called to initialize the high-level exception handling. + No high level exception handlers are installed yet. If an exception + occurs at this point, the system displays an error message and + terminates. */ + + static void dispatch_exception(REGS * _r); + /* This is the high-level exception dispatcher. It dispatches the exception + to the previously registered exception handler. + This function is called by the low-level function + "lowlevel_dispatch_exception(REGS * _r)".*/ + + /* -- MANAGE INSTANCES OF EXCEPTION HANDLERS */ + + virtual void handle_exception(REGS * _regs) { + assert(false); // sometimes pure virtual functions dont link correctly. + } + /* Different exception handlers are derived from the base class ExceptionHandler + and their functionality is implemented in this function.*/ + +}; + +#endif + + diff --git a/MP3/MP3_Sources/gdt.C b/MP3/MP3_Sources/gdt.C new file mode 100755 index 0000000..4e1cb55 --- /dev/null +++ b/MP3/MP3_Sources/gdt.C @@ -0,0 +1,124 @@ +/* + File: gdt.C + + Date : 09/03/02 + + Description: Management of the Global Descriptor Table (GDT) + + The GDT describes memory access priviledges for memory segments. + + While the table is initialized by GRUB already, it may be a good idea to + do this again in the kernel code. + + For details see Section 5 of Brandon Friesen's Tutorial + on OS Kernel Development. + URL: http://www.osdever.net/bkerndev/Docs/title.htm + +* bkerndev - Bran's Kernel Development Tutorial +* By: Brandon F. (friesenb@gmail.com) +* Desc: Interrupt Descriptor Table management +* +* Notes: No warranty expressed or implied. Use at own risk. +*/ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +//#include "assert.H" +#include "utils.H" +#include "gdt.H" + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + +/* Defines a GDT entry. We use the 'packed' directive to prevent the + compiler from optimizing by aligning structure elements at word + boundaries. */ +struct gdt_entry { + 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 that includes the limit: The max bytes + taken up by the GDT, minus 1. Again, this NEEDS to be packed. */ +struct gdt_ptr { + unsigned short limit; + unsigned int base; +} __attribute__((packed)); + +/*--------------------------------------------------------------------------*/ +/* VARIABLES */ +/*--------------------------------------------------------------------------*/ + +static struct gdt_entry gdt[GDT::SIZE]; +struct gdt_ptr gp; + +/*--------------------------------------------------------------------------*/ +/* EXTERNS */ +/*--------------------------------------------------------------------------*/ + +/* This function is defined in 'gdt_low.asm', which in turn is included in + 'start.asm'. */ +extern "C" void gdt_flush(); + +/*--------------------------------------------------------------------------*/ +/* EXPORTED FUNCTIONS */ +/*--------------------------------------------------------------------------*/ + +/* Use this function to set up an entry in the GDT. */ +void GDT::set_gate(int num, + unsigned long base, unsigned long limit, + unsigned char access, unsigned char gran) { + + /* 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; +} + + +/* Installs the GDT */ +void GDT::init() { + + /* Sets up the special GDT pointer. */ + gp.limit = (sizeof (struct gdt_entry) * SIZE) - 1; + gp.base = (unsigned int)&gdt; + + /* Our NULL descriptor */ + set_gate(0, 0, 0, 0, 0); + + /* The second entry is our Code Segment. The base address + is 0, the limit is 4GByte, it uses 4kB granularity, + uses 32-bit opcodes, and is a Code Segment descriptor. + Please check the GDT section in Bran's Kernel Development + tutorial to see exactly what each value means. */ + set_gate(1, 0, 0xFFFFFFFF, 0x9a, 0xCF); + + /* The third entry is our Data Segment. It's EXACTLY the + same as the code segment, but the descriptor type in + this entry's access byte says it's a Data Segment. */ + set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); + + /* Flush out the old GDT, and install the new changes. */ + gdt_flush(); +} diff --git a/MP3/MP3_Sources/gdt.H b/MP3/MP3_Sources/gdt.H new file mode 100755 index 0000000..ae9eb95 --- /dev/null +++ b/MP3/MP3_Sources/gdt.H @@ -0,0 +1,48 @@ +/* + File: gdt.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/03/02 + + Description: Management of the Global Descriptor Table (GDT) + + The GDT describes memory access priviledges for memory segments. + + While the table is initialized by GRUB already, it may be a good idea to + do this again in the kernel code. + + For details see Section 5 of Brandon Friesen's Tutotial + on OS Kernel Development. + URL: http://www.osdever.net/bkerndev/Docs/title.htm + +*/ + +#ifndef _GDT_H_ // include file only once +#define _GDT_H_ + +/*--------------------------------------------------------------------------*/ +/* GDT */ +/*--------------------------------------------------------------------------*/ + +class GDT { + +private: + + /* Use this function to set up an entry in the GDT. */ + static void set_gate(int num, + unsigned long base, unsigned long limit, + unsigned char access, unsigned char gran); + +public: + + static const unsigned int SIZE = 3; + + static void init(); + /* Initialize the GDT to have a null segment, a code segment, + and one data segment. */ + +}; + +#endif diff --git a/MP3/MP3_Sources/gdt_low.asm b/MP3/MP3_Sources/gdt_low.asm new file mode 100755 index 0000000..0b15df0 --- /dev/null +++ b/MP3/MP3_Sources/gdt_low.asm @@ -0,0 +1,18 @@ +; 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 ; Allows the C code to link to this. +extern _gp ; Says that '_gp' is in another file + +_gdt_flush: + lgdt[_gp] ; Load the GDT with our '_gp', 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! diff --git a/MP3/MP3_Sources/idt.C b/MP3/MP3_Sources/idt.C new file mode 100755 index 0000000..76d93ca --- /dev/null +++ b/MP3/MP3_Sources/idt.C @@ -0,0 +1,108 @@ +/* + File: idt.C + + Date : 09/03/02 + +*/ + +/* Based largely on +* bkerndev - Bran's Kernel Development Tutorial +* By: Brandon F. (friesenb@gmail.com) +* Desc: Interrupt Descriptor Table management +* +* Notes: No warranty expressed or implied. Use at own risk. */ + + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +//#include "assert.H" +#include "utils.H" +#include "idt.H" +#include "console.H" + +/*--------------------------------------------------------------------------*/ +/* EXTERNS */ +/*--------------------------------------------------------------------------*/ + +/* Used to load our IDT, defined in 'idt_low.s' */ +extern "C" void idt_load(); + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + +struct idt_entry +{ + unsigned short base_lo; + unsigned short sel; + unsigned char always0; + unsigned char flags; + unsigned short base_hi; +} __attribute__((packed)); + +struct idt_ptr +{ + unsigned short limit; + unsigned int base; +} __attribute__((packed)); + + +/*--------------------------------------------------------------------------*/ +/* VARIABLES */ +/*--------------------------------------------------------------------------*/ + + +/* Declare an IDT of IDT_SIZE entries. We use only the first 32 + entries. If any undefined IDT entry is hit, it normally + cause an "Unhandled Interrupt" exception. Any descriptor + for which the 'presence' bit is cleared will generate an + "Unhandled Interrupt" exception. */ +struct idt_entry idt[IDT::SIZE]; +struct idt_ptr idtp; + +/*--------------------------------------------------------------------------*/ +/* HOOKING UP THE LOW-LEVEL EXCEPTION HANDLER TO EXCEPTIONDISPATCHER. */ +/*--------------------------------------------------------------------------*/ + +/* Use this function to set an entry in the IDT. */ +void IDT::set_gate(unsigned char num, unsigned long base, + unsigned short sel, unsigned char flags) { + + Console::puts("Installing handler in IDT position "); + Console::puti((int)num); + Console::puts("\n"); + + /* 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; + +} + +/* Installs the IDT */ +void IDT::init() { + + /* Sets the special IDT pointer up. */ + idtp.limit = (sizeof (struct idt_entry) * 256) - 1; + idtp.base = (unsigned int)&idt; + + /* Clear out the entire IDT, initializing it to zeros. */ + memset(&idt, 0, sizeof(struct idt_entry) * 256); + + + /* Points the processor's internal register to the new IDT */ + idt_load(); +} diff --git a/MP3/MP3_Sources/idt.H b/MP3/MP3_Sources/idt.H new file mode 100755 index 0000000..ee0bd54 --- /dev/null +++ b/MP3/MP3_Sources/idt.H @@ -0,0 +1,57 @@ +/* + File: idt.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/03/02 + + Description: the Interrupt Description Table (IDT) + + The IDT contains pointer to low-level exception and interrupt handlers. + The way the exception handling is set up, all low-level handlers route + the exception to a single exception dispatcher, which in turn + calls a high-level exception dispatcher (see file 'exceptions.H'). + + For details see Section 6 of Brandon Friesen's Tutorial + on OS Kernel Development. + URL: http://www.osdever.net/bkerndev/Docs/title.htm + +*/ + +#ifndef _IDT_H_ // include file only once +#define _IDT_H_ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +//#define IDT_SIZE 256 + +/*--------------------------------------------------------------------------*/ +/* Class IDT */ +/*--------------------------------------------------------------------------*/ + +class IDT { + + public: + + static const int SIZE = 256; + + static void init(); + /* Initialize the IDT, and fill the 32 first entries with pointers to handle + the 32 Intel-defined exceptions. After initializing the IDT, these exceptions + are routed to the exception dispatcher (see 'exceptions.H'). At this point, + no exception handlers are installed yet. + */ + + static void set_gate(unsigned char num, unsigned long base, + unsigned short sel, unsigned char flags); + /* Used to install a low-level exception handler in the IDT. For high-level + exception handlers, use the exception management framework defined in + file 'exceptions.H'. + */ + +}; + +#endif diff --git a/MP3/MP3_Sources/idt_low.asm b/MP3/MP3_Sources/idt_low.asm new file mode 100755 index 0000000..9312d38 --- /dev/null +++ b/MP3/MP3_Sources/idt_low.asm @@ -0,0 +1,279 @@ +; This is the exception de-multiplexer code. +; All low-level exception handling routines do the following: +; 1. disable interrupts +; 2. push error code on the stack (if the exception did not already +; do so! (Some exceptions automatically push the error code onto the +; stack.) +; 3. push the number of the exception onto the stack. +; 4. call the common interrupt service routine function, which then +; branches back out based on the exception number on the stack. +; (We do this because we don't want to replicate again and again the code +; to save the processor state.) +; + +; Here come the interrupt service routines for the 32 exceptions. +global _isr0 +global _isr1 +global _isr2 +global _isr3 +global _isr4 +global _isr5 +global _isr6 +global _isr7 +global _isr8 +global _isr9 +global _isr10 +global _isr11 +global _isr12 +global _isr13 +global _isr14 +global _isr15 +global _isr16 +global _isr17 +global _isr18 +global _isr19 +global _isr20 +global _isr21 +global _isr22 +global _isr23 +global _isr24 +global _isr25 +global _isr26 +global _isr27 +global _isr28 +global _isr29 +global _isr30 +global _isr31 + + +extern _promptA +extern _promptB +extern _promptC + + +; 0: Divide By Zero Exception +_isr0: + push byte 0 + push byte 0 + jmp isr_common_stub + +; 1: Debug Exception +_isr1: + push byte 0 + push byte 1 + jmp isr_common_stub + +; 2: Non Maskable Interrupt Exception +_isr2: + push byte 0 + push byte 2 + jmp isr_common_stub + +; 3: Int 3 Exception +_isr3: + push byte 0 + push byte 3 + jmp isr_common_stub + +; 4: INTO Exception +_isr4: + push byte 0 + push byte 4 + jmp isr_common_stub + +; 5: Out of Bounds Exception +_isr5: + push byte 0 + push byte 5 + jmp isr_common_stub + +; 6: Invalid Opcode Exception +_isr6: + push byte 0 + push byte 6 + jmp isr_common_stub + +; 7: Coprocessor Not Available Exception +_isr7: + push byte 0 + push byte 7 + jmp isr_common_stub + +; 8: Double Fault Exception (With Error Code!) +_isr8: + push byte 8 + jmp isr_common_stub + +; 9: Coprocessor Segment Overrun Exception +_isr9: + push byte 0 + push byte 9 + jmp isr_common_stub + +; 10: Bad TSS Exception (With Error Code!) +_isr10: + push byte 10 + jmp isr_common_stub + +; 11: Segment Not Present Exception (With Error Code!) +_isr11: + push byte 11 + jmp isr_common_stub + +; 12: Stack Fault Exception (With Error Code!) +_isr12: + push byte 12 + jmp isr_common_stub + +; 13: General Protection Fault Exception (With Error Code!) +_isr13: + push byte 13 + jmp isr_common_stub + +; 14: Page Fault Exception (With Error Code!) +_isr14: + push byte 14 + jmp isr_common_stub + +; 15: Reserved Exception +_isr15: + push byte 0 + push byte 15 + jmp isr_common_stub + +; 16: Floating Point Exception +_isr16: + push byte 0 + push byte 16 + jmp isr_common_stub + +; 17: Alignment Check Exception +_isr17: + push byte 0 + push byte 17 + jmp isr_common_stub + +; 18: Machine Check Exception +_isr18: + push byte 0 + push byte 18 + jmp isr_common_stub + +; 19: Reserved +_isr19: + push byte 0 + push byte 19 + jmp isr_common_stub + +; 20: Reserved +_isr20: + push byte 0 + push byte 20 + jmp isr_common_stub + +; 21: Reserved +_isr21: + push byte 0 + push byte 21 + jmp isr_common_stub + +; 22: Reserved +_isr22: + push byte 0 + push byte 22 + jmp isr_common_stub + +; 23: Reserved +_isr23: + push byte 0 + push byte 23 + jmp isr_common_stub + +; 24: Reserved +_isr24: + push byte 0 + push byte 24 + jmp isr_common_stub + +; 25: Reserved +_isr25: + push byte 0 + push byte 25 + jmp isr_common_stub + +; 26: Reserved +_isr26: + push byte 0 + push byte 26 + jmp isr_common_stub + +; 27: Reserved +_isr27: + push byte 0 + push byte 27 + jmp isr_common_stub + +; 28: Reserved +_isr28: + push byte 0 + push byte 28 + jmp isr_common_stub + +; 29: Reserved +_isr29: + push byte 0 + push byte 29 + jmp isr_common_stub + +; 30: Reserved +_isr30: + push byte 0 + push byte 30 + jmp isr_common_stub + +; 31: Reserved +_isr31: + push byte 0 + push byte 31 + jmp isr_common_stub + + + +; The common stub below will pun out into C. Let the +; assembler know that the function is defined in 'exceptions.C'. +extern _lowlevel_dispatch_exception + +; This is the common low-level stub for the exception handler. +; It saves the processor state, sets up for kernel mode +; segments, calls the C-level exception handler, +; and finally restores the stack frame. +isr_common_stub: + pusha + push ds + push es + push fs + push gs + + mov eax, esp ; Push us the stack + push eax + mov eax, _lowlevel_dispatch_exception + call eax ; A special call, preserves the 'eip' register + pop eax + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 ; Ceans up the pushed error code and pushed ISR number + iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP1 + + + +; load the IDT defined in '_idtp' into the processor. +; This is declared in C as 'extern void _idt_load();' +; In turn, the variable '_idtp' is defined in file 'idt.C'. +global _idt_load +extern _idtp +_idt_load: + lidt [_idtp] + ret diff --git a/MP3/MP3_Sources/interrupts.C b/MP3/MP3_Sources/interrupts.C new file mode 100755 index 0000000..c67fba5 --- /dev/null +++ b/MP3/MP3_Sources/interrupts.C @@ -0,0 +1,172 @@ +/* + File: interrupts.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 12/09/05 + +*/ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +/* (none) */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "assert.H" +#include "utils.H" +#include "console.H" +#include "idt.H" +#include "irq.H" +#include "exceptions.H" +#include "interrupts.H" + +/*--------------------------------------------------------------------------*/ +/* EXTERNS */ +/*--------------------------------------------------------------------------*/ + +/* The low-level functions (defined in file 'irq_low.s') that handle the + 16 PIC-generated interrupts. + These functions are actually merely stubs that put the error code and + the exception code on the stack and then call a low-level function, which + in turn calls the interrupt dispatcher. + Yes, there are more efficient ways to handle exceptions, but they require more + code replication. +*/ + +extern "C" void irq0(); +extern "C" void irq1(); +extern "C" void irq2(); +extern "C" void irq3(); +extern "C" void irq4(); +extern "C" void irq5(); +extern "C" void irq6(); +extern "C" void irq7(); +extern "C" void irq8(); +extern "C" void irq9(); +extern "C" void irq10(); +extern "C" void irq11(); +extern "C" void irq12(); +extern "C" void irq13(); +extern "C" void irq14(); +extern "C" void irq15(); + +extern "C" void lowlevel_dispatch_interrupt(REGS * _r) { + InterruptHandler::dispatch_interrupt(_r); +} + +/*--------------------------------------------------------------------------*/ +/* LOCAL VARIABLES */ +/*--------------------------------------------------------------------------*/ + +InterruptHandler * InterruptHandler::handler_table[InterruptHandler::IRQ_TABLE_SIZE]; + +/*--------------------------------------------------------------------------*/ +/* EXPORTED INTERRUPT DISPATCHER FUNCTIONS */ +/*--------------------------------------------------------------------------*/ + +void InterruptHandler::init_dispatcher() { + + /* -- INITIALIZE LOW-LEVEL INTERRUPT HANDLERS */ + /* Add any new ISRs to the IDT here using IDT::set_gate */ + IDT::set_gate( 0+ IRQ_BASE, (unsigned) irq0, 0x08, 0x8E); + IDT::set_gate( 1+ IRQ_BASE, (unsigned) irq1, 0x08, 0x8E); + IDT::set_gate( 2+ IRQ_BASE, (unsigned) irq2, 0x08, 0x8E); + IDT::set_gate( 3+ IRQ_BASE, (unsigned) irq3, 0x08, 0x8E); + IDT::set_gate( 4+ IRQ_BASE, (unsigned) irq4, 0x08, 0x8E); + IDT::set_gate( 5+ IRQ_BASE, (unsigned) irq5, 0x08, 0x8E); + IDT::set_gate( 6+ IRQ_BASE, (unsigned) irq6, 0x08, 0x8E); + IDT::set_gate( 7+ IRQ_BASE, (unsigned) irq7, 0x08, 0x8E); + + IDT::set_gate( 8+ IRQ_BASE, (unsigned) irq8, 0x08, 0x8E); + IDT::set_gate( 9+ IRQ_BASE, (unsigned) irq9, 0x08, 0x8E); + IDT::set_gate(10+ IRQ_BASE, (unsigned)irq10, 0x08, 0x8E); + IDT::set_gate(11+ IRQ_BASE, (unsigned)irq11, 0x08, 0x8E); + IDT::set_gate(12+ IRQ_BASE, (unsigned)irq12, 0x08, 0x8E); + IDT::set_gate(13+ IRQ_BASE, (unsigned)irq13, 0x08, 0x8E); + IDT::set_gate(14+ IRQ_BASE, (unsigned)irq14, 0x08, 0x8E); + IDT::set_gate(15+ IRQ_BASE, (unsigned)irq15, 0x08, 0x8E); + + /* -- INITIALIZE THE HIGH-LEVEL INTERRUPT HANDLER */ + int i; + for(i = 0; i < IRQ_TABLE_SIZE; i++) { + handler_table[i] = NULL; + } +} + +bool InterruptHandler::generated_by_slave_PIC(unsigned int int_no) { + return int_no > 7; +} + +void InterruptHandler::dispatch_interrupt(REGS * _r) { + + /* -- INTERRUPT NUMBER */ + unsigned int int_no = _r->int_no - IRQ_BASE; + + //Console::puts("INTERRUPT DISPATCHER: int_no = "); + //Console::putui(int_no); + //Console::puts("\n"); + + assert((int_no >= 0) && (int_no < IRQ_TABLE_SIZE)); + + /* -- HAS A HANDLER BEEN REGISTERED FOR THIS INTERRUPT NO? */ + + InterruptHandler * handler = handler_table[int_no]; + + if (!handler) { + /* --- NO DEFAULT HANDLER HAS BEEN REGISTERED. SIMPLY RETURN AN ERROR. */ + Console::puts("INTERRUPT NO: "); + Console::puti(int_no); + Console::puts("\n"); + Console::puts("NO DEFAULT INTERRUPT HANDLER REGISTERED\n"); + // abort(); + } + else { + /* -- HANDLE THE INTERRUPT */ + handler->handle_interrupt(_r); + } + + /* This is an interrupt that was raised by the interrupt controller. We need + to send and end-of-interrupt (EOI) signal to the controller after the + interrupt has been handled. */ + + /* Check if the interrupt was generated by the slave interrupt controller. + If so, send an End-of-Interrupt (EOI) message to the slave controller. */ + + if (generated_by_slave_PIC(int_no)) { + Machine::outportb(0xA0, 0x20); + } + + /* Send an EOI message to the master interrupt controller. */ + Machine::outportb(0x20, 0x20); + +} + +void InterruptHandler::register_handler(unsigned int _irq_code, + InterruptHandler * _handler) { + assert(_irq_code >= 0 && _irq_code < IRQ_TABLE_SIZE); + + handler_table[_irq_code] = _handler; + + Console::puts("Installed interrupt handler at IRQ "); + Console::putui(_irq_code); + Console::puts("\n"); + +} + +void InterruptHandler::deregister_handler(unsigned int _irq_code) { + + assert(_irq_code >= 0 && _irq_code < IRQ_TABLE_SIZE); + + handler_table[_irq_code] = NULL; + + Console::puts("UNINSTALLED interrupt handler at IRQ "); + Console::putui(_irq_code); + Console::puts("\n"); + +} diff --git a/MP3/MP3_Sources/interrupts.H b/MP3/MP3_Sources/interrupts.H new file mode 100755 index 0000000..fd35216 --- /dev/null +++ b/MP3/MP3_Sources/interrupts.H @@ -0,0 +1,90 @@ +/* + File: interrupts.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 11/11/10 + + Description: High-level interrupt handling. + + CPU exceptions are caught by low-level exception and interrupt + handler stubs, which all eventually cause the high-level + exception dispatcher to be called (see 'dispatch_exception() below). + + The dispatcher then looks up the appropriate exception handler + for the given exception, and calls it. + Specific exception handlers are installed by registering an exception handler + object of a class appropriately derived from class 'ExceptionHandler'. The + functionality of the exception handler is then implemented in function + 'handle_exception(REGS * _regs)'. +*/ + +#ifndef _interrupts_H_ // include file only once +#define _interrupts_H_ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "assert.H" +#include "machine.H" +#include "exceptions.H" + +/*--------------------------------------------------------------------------*/ +/* I n t e r r u p t H a n d l e r */ +/*--------------------------------------------------------------------------*/ + +class InterruptHandler { + + private: + + /* The Interrupt Handler Table */ + const static int IRQ_TABLE_SIZE = 16; + const static int IRQ_BASE = 32; + + static InterruptHandler * handler_table[IRQ_TABLE_SIZE]; + + static bool generated_by_slave_PIC(unsigned int int_no); + /* Has the particular interupt been generated by the Slave PIC? */ + + public: + + /* -- POPULATE INTERRUPT-DISPATCHER TABLE */ + static void register_handler(unsigned int _irq_code, + InterruptHandler * _handler); + /* This function allows to install an interrupt handler for the given + Interrupt code. The handler is a function pointer defined above. + Interrupt handlers are installed as Interrupt handlers as well. + The 'register_interrupt' function uses irq2isr to map the IRQ + number to the code. */ + + static void deregister_handler(unsigned int _irq_code); + + /* -- INITIALIZER */ + static void init_dispatcher(); + /* This function is called to initialize the high-level interrupt + handling. No high level interrupt handlers are installed yet. + If an interrupt occurs at this point, the system displays an error + message and terminates. */ + + static void dispatch_interrupt(REGS * _r); + /* This is the high-level interrupt dispatcher. It dispatches the interrupt + to the previously registered interrupt handler. + This function is called by the low-level function + "lowlevel_dispatch_interrupt(REGS * _r)".*/ + + /* -- MANAGE INSTANCES OF INTERRUPT HANDLERS */ + + virtual void handle_interrupt(REGS * _regs) { + assert(false); // sometimes pure virtual functions don't link correctly. + } + /* Different interrupt handlers are derived from the base class + InterruptHandler, and their functionality is implemented in + this function.*/ + +}; + +#endif + + diff --git a/MP3/MP3_Sources/irq.C b/MP3/MP3_Sources/irq.C new file mode 100755 index 0000000..44f27c0 --- /dev/null +++ b/MP3/MP3_Sources/irq.C @@ -0,0 +1,60 @@ +/* + File: irq.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/03/05 + + This code borrows heavily from Brandon Friesen's the code in Brandon + Friesen's OS Development Tutorial. +*/ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +#define IRQ_BASE 32 + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "machine.H" +#include "irq.H" + +/*--------------------------------------------------------------------------*/ +/* LOCAL FUNCTIONS . */ +/*--------------------------------------------------------------------------*/ + +/* Normally, IRQs 0 to 7 are mapped to IDT entries 8 to 15. + For a variety of reasons it is a good idea to re-map these + IRQs to different locations + We send a sequence of commands to the PICs - 8259's - in order + to have IRQ0 to IRQ15 be remapped to IDT entries 32 to 47. +*/ +static void irq_remap() +{ + Machine::outportb(0x20, 0x11); + Machine::outportb(0xA0, 0x11); + Machine::outportb(0x21, 0x20); + Machine::outportb(0xA1, 0x28); + Machine::outportb(0x21, 0x04); + Machine::outportb(0xA1, 0x02); + Machine::outportb(0x21, 0x01); + Machine::outportb(0xA1, 0x01); + Machine::outportb(0x21, 0x0); + Machine::outportb(0xA1, 0x0); +} + + +/*--------------------------------------------------------------------------*/ +/* EXPORTED FUNCTIONS . */ +/*--------------------------------------------------------------------------*/ + +void IRQ::init() { + + irq_remap(); + + +} diff --git a/MP3/MP3_Sources/irq.H b/MP3/MP3_Sources/irq.H new file mode 100755 index 0000000..0072f9b --- /dev/null +++ b/MP3/MP3_Sources/irq.H @@ -0,0 +1,38 @@ +/* + File: irq.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/03/02 + + Description: Interrupt Table (IRQ) + + For details see Section 7 of Brandon Friesen's Tutorial + on OS Kernel Development. + URL: http://www.osdever.net/bkerndev/Docs/title.htm + +*/ + +#ifndef _IRQ_H_ // include file only once +#define _IRQ_H_ + + +/*--------------------------------------------------------------------------*/ +/* */ +/*--------------------------------------------------------------------------*/ + +class IRQ { + +public: + + static void init(); + /* Initialize the IRQ handlers, i.e. fill 16 entries with pointers to handle + the PIC generated interrupts. These interrupts are routed to the exception + dispatcher (see 'exceptions.H'). At this point, no exception handlers are + installed yet. + */ + +}; + +#endif diff --git a/MP3/MP3_Sources/irq_low.asm b/MP3/MP3_Sources/irq_low.asm new file mode 100755 index 0000000..e94271c --- /dev/null +++ b/MP3/MP3_Sources/irq_low.asm @@ -0,0 +1,136 @@ +global _irq0 +global _irq1 +global _irq2 +global _irq3 +global _irq4 +global _irq5 +global _irq6 +global _irq7 +global _irq8 +global _irq9 +global _irq10 +global _irq11 +global _irq12 +global _irq13 +global _irq14 +global _irq15 + +; 32: IRQ0 +_irq0: + push byte 0 + push byte 32 + jmp irq_common_stub + +; 33: IRQ1 +_irq1: + push byte 0 + push byte 33 + jmp irq_common_stub + +; 34: IRQ2 +_irq2: + push byte 0 + push byte 34 + jmp irq_common_stub + +; 35: IRQ3 +_irq3: + push byte 0 + push byte 35 + jmp irq_common_stub + +; 36: IRQ4 +_irq4: + push byte 0 + push byte 36 + jmp irq_common_stub + +; 37: IRQ5 +_irq5: + push byte 0 + push byte 37 + jmp irq_common_stub + +; 38: IRQ6 +_irq6: + push byte 0 + push byte 38 + jmp irq_common_stub + +; 39: IRQ7 +_irq7: + push byte 0 + push byte 39 + jmp irq_common_stub + +; 40: IRQ8 +_irq8: + push byte 0 + push byte 40 + jmp irq_common_stub + +; 41: IRQ9 +_irq9: + push byte 0 + push byte 41 + jmp irq_common_stub + +; 42: IRQ10 +_irq10: + push byte 0 + push byte 42 + jmp irq_common_stub + +; 43: IRQ11 +_irq11: + push byte 0 + push byte 43 + jmp irq_common_stub + +; 44: IRQ12 +_irq12: + push byte 0 + push byte 44 + jmp irq_common_stub + +; 45: IRQ13 +_irq13: + push byte 0 + push byte 45 + jmp irq_common_stub + +; 46: IRQ14 +_irq14: + push byte 0 + push byte 46 + jmp irq_common_stub + +; 47: IRQ15 +_irq15: + push byte 0 + push byte 47 + jmp irq_common_stub + +extern _lowlevel_dispatch_interrupt + +irq_common_stub: + pusha + push ds + push es + push fs + push gs + + mov eax, esp + + push eax + mov eax, _lowlevel_dispatch_interrupt + call eax + pop eax + + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 + iret diff --git a/MP3/MP3_Sources/kernel.C b/MP3/MP3_Sources/kernel.C new file mode 100755 index 0000000..884f1f4 --- /dev/null +++ b/MP3/MP3_Sources/kernel.C @@ -0,0 +1,196 @@ +/* + File: kernel.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 12/09/03 + + + This file has the main entry point to the operating system. + + */ + + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "machine.H" /* LOW-LEVEL STUFF */ +#include "console.H" +#include "gdt.H" +#include "idt.H" /* LOW-LEVEL EXCEPTION MGMT. */ +#include "irq.H" +#include "exceptions.H" +#include "interrupts.H" + +#include "simple_keyboard.H" /* SIMPLE KB DRIVER */ +#include "simple_timer.H" /* TIMER MANAGEMENT */ + +#include "page_table.H" +#include "paging_low.H" + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +#define MB * (0x1 << 20) +#define KB * (0x1 << 10) +#define KERNEL_POOL_START_FRAME ((2 MB) / Machine::PAGE_SIZE) +#define KERNEL_POOL_SIZE ((2 MB) / Machine::PAGE_SIZE) +#define PROCESS_POOL_START_FRAME ((4 MB) / Machine::PAGE_SIZE) +#define PROCESS_POOL_SIZE ((28 MB) / Machine::PAGE_SIZE) +/* definition of the kernel and process memory pools */ + +#define MEM_HOLE_START_FRAME ((15 MB) / Machine::PAGE_SIZE) +#define MEM_HOLE_SIZE ((1 MB) / Machine::PAGE_SIZE) +/* we have a 1 MB hole in physical memory starting at address 15 MB */ + +#define FAULT_ADDR (4 MB) +/* used in the code later as address referenced to cause page faults. */ +#define NACCESS ((1 MB) / 4) +/* NACCESS integer access (i.e. 4 bytes in each access) are made starting at address FAULT_ADDR */ + +/*--------------------------------------------------------------------------*/ +/* MAIN ENTRY INTO THE OS */ +/*--------------------------------------------------------------------------*/ + +int main() { + + GDT::init(); + Console::init(); + IDT::init(); + ExceptionHandler::init_dispatcher(); + IRQ::init(); + InterruptHandler::init_dispatcher(); + + + /* -- EXAMPLE OF AN EXCEPTION HANDLER: Division-by-Zero -- */ + + class DBZ_Handler : public ExceptionHandler { + /* We derive Division-by-Zero handler from ExceptionHandler + and overload the method handle_exception. */ + public: + virtual void handle_exception(REGS * _regs) { + Console::puts("DIVISION BY ZERO!\n"); + for(;;); + } + } dbz_handler; + + /* Register the DBZ handler for exception no.0 + with the exception dispatcher. */ + ExceptionHandler::register_handler(0, &dbz_handler); + + + /* -- EXAMPLE OF AN INTERRUPT HANDLER: Very simple timer -- */ + + SimpleTimer timer(100); /* timer ticks every 10ms. */ + + /* ---- Register timer handler for interrupt no.0 + with the interrupt dispatcher. */ + InterruptHandler::register_handler(0, &timer); + + /* NOTE: The timer chip starts periodically firing as + soon as we enable interrupts. + It is important to install a timer handler, as we + would get a lot of uncaptured interrupts otherwise. */ + + /* -- INSTALL INTERRUPT HANDLER FOR SIMPLE KEYBOARD -- */ + + SimpleKeyboard::init(); + + /* NOTE: In the SimpleKeyboard::init() a private static object of + type SimpleKeyboard is created and its interrupt handler is + registered with the interrupt dispatcher. Subsequent calls to the + static function SimpleKeyboard::wait() look until a key is pressed.*/ + + /* -- ENABLE INTERRUPTS -- */ + + Machine::enable_interrupts(); + + /* -- INITIALIZE FRAME POOLS -- */ + + ContFramePool kernel_mem_pool(KERNEL_POOL_START_FRAME, + KERNEL_POOL_SIZE, + 0, + 0); + + unsigned long n_info_frames = ContFramePool::needed_info_frames(PROCESS_POOL_SIZE); + + unsigned long process_mem_pool_info_frame = kernel_mem_pool.get_frames(n_info_frames); + + ContFramePool process_mem_pool(PROCESS_POOL_START_FRAME, + PROCESS_POOL_SIZE, + process_mem_pool_info_frame, + n_info_frames); + + /* Take care of the hole in the memory. */ + process_mem_pool.mark_inaccessible(MEM_HOLE_START_FRAME, MEM_HOLE_SIZE); + + /* -- INITIALIZE MEMORY (PAGING) -- */ + + /* ---- INSTALL PAGE FAULT HANDLER -- */ + + class PageFault_Handler : public ExceptionHandler { + /* We derive the page fault handler from ExceptionHandler + and overload the method handle_exception. */ + public: + virtual void handle_exception(REGS * _regs) { + PageTable::handle_fault(_regs); + } + } pagefault_handler; + + /* ---- Register the page fault handler for exception no.14 + with the exception dispatcher. */ + ExceptionHandler::register_handler(14, &pagefault_handler); + + /* ---- INITIALIZE THE PAGE TABLE -- */ + + PageTable::init_paging(&kernel_mem_pool, + &process_mem_pool, + 4 MB); /* We share the first 4MB */ + + PageTable pt; + + pt.load(); + + PageTable::enable_paging(); + + Console::puts("WE TURNED ON PAGING!\n"); + Console::puts("If we see this message, the page tables have been\n"); + Console::puts("set up mostly correctly.\n"); + + /* -- MOST OF WHAT WE NEED IS SETUP. THE KERNEL CAN START. */ + + Console::puts("Hello World!\n"); + + /* -- GENERATE MEMORY REFERENCES */ + + int *foo = (int *) FAULT_ADDR; + int i; + + for (i=0; iget_frames(1); // Need to take one frame for page directory. + + //page_directory = (unsigned long *) 0x32000; // Should be the starting address after 1st 2MB + page_directory = (unsigned long *) kernel_mem_pool->get_frames(1); // Should I get the address like this??? + + //unsigned long * page_table = (unsigned long *) 0x33000; // Should be 4kb after the page directory. + unsigned long * page_table = page_directory + 0x1000; // Might be able to just do this. + + unsigned long tempaddr; // Temporary address iterator. + + // We need to map the first 4MB. + for(unsigned int i = 0; i < 1024; i++) + { + page_table[i] = tempaddr | 3; // set bits 0 and 1 to present and read/write respectively + tempaddr += 4096; // 4096 = 4kb + } + + + // Fill first entry of page directory. + page_directory[0] = *page_table; + page_directory[0] = page_directory[0] | 3; + + for(unsigned int j = 1; j < 1024; j++) + { + page_directory[j] = 0 | 2; + } + + current_page_table = this; + + Console::puts("\nConstructed Page Table object\n"); +} + + +void PageTable::load() +{ + write_cr3(*page_directory); + current_page_table = this; + Console::puts("\nLoaded page table\n"); +} + +void PageTable::enable_paging() +{ + write_cr3(*current_page_table->page_directory); + write_cr0(read_cr0() | 0x80000000); + paging_enabled = read_cr0(); + Console::puts("\nEnabled paging\n"); +} + +void PageTable::handle_fault(REGS * _r) +{ + /* + unsigned long tempframe = process_mem_pool->get_frames(1); + Console::puts("\nerror code: "); + Console::puti(_r->err_code); + + unsigned char mask = 0x00; + + + read_cr2(); +*/ + assert(false); + Console::puts("\nhandled page fault\n"); +} + diff --git a/MP3/MP3_Sources/page_table.H b/MP3/MP3_Sources/page_table.H new file mode 100755 index 0000000..f89e5a1 --- /dev/null +++ b/MP3/MP3_Sources/page_table.H @@ -0,0 +1,91 @@ +/* + File: page_table.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 16/12/07 + + Description: Basic Paging. + +*/ + +#ifndef _page_table_H_ // include file only once +#define _page_table_H_ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "machine.H" +#include "exceptions.H" +#include "cont_frame_pool.H" + +/*--------------------------------------------------------------------------*/ +/* FORWARDS */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* P A G E - T A B L E */ +/*--------------------------------------------------------------------------*/ + +class PageTable { + +private: + + /* THESE MEMBERS ARE COMMON TO ENTIRE PAGING SUBSYSTEM */ + static PageTable * current_page_table; /* pointer to currently loaded page table object */ + static unsigned int paging_enabled; /* is paging turned on (i.e. are addresses logical)? */ + static ContFramePool * kernel_mem_pool; /* Frame pool for the kernel memory */ + static ContFramePool * process_mem_pool; /* Frame pool for the process memory */ + static unsigned long shared_size; /* size of shared address space */ + + /* DATA FOR CURRENT PAGE TABLE */ + unsigned long * page_directory; /* where is page directory located? */ + +public: + static const unsigned int PAGE_SIZE = Machine::PAGE_SIZE; + /* in bytes */ + static const unsigned int ENTRIES_PER_PAGE = Machine::PT_ENTRIES_PER_PAGE; + /* in entries, duh! */ + + static void init_paging(ContFramePool * _kernel_mem_pool, + ContFramePool * _process_mem_pool, + const unsigned long _shared_size); + /* Set the global parameters for the paging subsystem. */ + + PageTable(); + /* Initializes a page table with a given location for the directory and the + page table proper. + NOTE: The PageTable object still needs to be stored somewhere! + Probably it is best to have it on the stack, as there is no + memory manager yet... + NOTE2: It may also be simpler to create the first page table *before* + paging has been enabled. + */ + + void load(); + /* Makes the given page table the current table. This must be done once during + system startup and whenever the address space is switched (e.g. during + process switching). */ + + static void enable_paging(); + /* Enable paging on the CPU. Typically, a CPU start with paging disabled, and + memory is accessed by addressing physical memory directly. After paging is + enabled, memory is addressed logically. */ + + static void handle_fault(REGS * _r); + /* The page fault handler. */ + +}; + +#endif + diff --git a/MP3/MP3_Sources/paging_low.H b/MP3/MP3_Sources/paging_low.H new file mode 100755 index 0000000..f36603a --- /dev/null +++ b/MP3/MP3_Sources/paging_low.H @@ -0,0 +1,51 @@ +/* + File: paging_low.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/03/28 + + + Low-level register operations for x86 paging subsystem. + +*/ + +#ifndef _paging_low_H_ // include file only once +#define _paging_low_H_ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +/* -- none -- */ + +/*--------------------------------------------------------------------------*/ +/* FORWARDS */ +/*--------------------------------------------------------------------------*/ + +/* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* LOW-LEVEL PAGING ROUTINES */ +/*--------------------------------------------------------------------------*/ + +/* The low-level functions (defined in file 'paging_low.asm') that handle the + low-level function to manage the page tables. */ + + +/* -- CR0 -- */ +extern "C" unsigned long read_cr0(); +extern "C" void write_cr0(unsigned long _val); + +/* -- CR2 -- */ +extern "C" unsigned long read_cr2(); + +/* -- CR3 -- */ +extern "C" unsigned long read_cr3(); +extern "C" void write_cr3(unsigned long _val); + + +#endif + + diff --git a/MP3/MP3_Sources/paging_low.asm b/MP3/MP3_Sources/paging_low.asm new file mode 100755 index 0000000..071a775 --- /dev/null +++ b/MP3/MP3_Sources/paging_low.asm @@ -0,0 +1,32 @@ +global _read_cr0 +_read_cr0: + mov eax, cr0 + retn + +global _write_cr0 +_write_cr0: + push ebp + mov ebp, esp + mov eax, [ebp+8] + mov cr0, eax + pop ebp + retn + +global _read_cr2 +_read_cr2: + mov eax, cr2 + retn + +global _read_cr3 +_read_cr3: + mov eax, cr3 + retn + +global _write_cr3 +_write_cr3: + push ebp + mov ebp, esp + mov eax, [ebp+8] + mov cr3, eax + pop ebp + retn \ No newline at end of file diff --git a/MP3/MP3_Sources/simple_keyboard.C b/MP3/MP3_Sources/simple_keyboard.C new file mode 100755 index 0000000..f821d80 --- /dev/null +++ b/MP3/MP3_Sources/simple_keyboard.C @@ -0,0 +1,79 @@ +/* + File: simple_keyboard.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 2017/06/30 + + Simple control of the keyboard. + */ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + +/* (none) */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "assert.H" +#include "machine.H" +#include "console.H" +#include "interrupts.H" +#include "simple_keyboard.H" + +/*--------------------------------------------------------------------------*/ +/* CONSTRUCTOR */ +/*--------------------------------------------------------------------------*/ + +SimpleKeyboard::SimpleKeyboard() { + key_pressed = false; +} + +/*--------------------------------------------------------------------------*/ +/* METHODS FOR CLASS S i m p l e K e y b o a r d */ +/*--------------------------------------------------------------------------*/ + +void SimpleKeyboard::handle_interrupt(REGS *_r) { + /* What to do when keyboard interrupt occurs? In this case, we update + "key_pressed". */ + + unsigned char status = Machine::inportb(STATUS_PORT); + /* lowest bit of status will be set if buffer is not empty. */ + if (status & 0x01) { + char kc = Machine::inportb(DATA_PORT); + if (kc >= 0) { + key_pressed = true; + key_code = kc; + } + } +} + +void SimpleKeyboard::wait() { + /* Loop until the user presses a key. */ + + kb.key_pressed = false; + + while(kb.key_pressed == false); + +} + +char SimpleKeyboard::read() { + /* Loop until the user presses a key, and then return the keycode. */ + kb.key_pressed = false; + + while (kb.key_pressed == false); + + return kb.key_code; +} + +SimpleKeyboard SimpleKeyboard::kb; + +void SimpleKeyboard::init() { + InterruptHandler::register_handler(1, &kb); +} + + diff --git a/MP3/MP3_Sources/simple_keyboard.H b/MP3/MP3_Sources/simple_keyboard.H new file mode 100755 index 0000000..823c09c --- /dev/null +++ b/MP3/MP3_Sources/simple_keyboard.H @@ -0,0 +1,68 @@ +/* + File: simple_keyboard.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 2017/02/17 + + Implements an interrupt handler for the keyboard. + The function is implemented in 'handle_interrupt'. + +*/ + +#ifndef _SIMPLE_KEYBOARD_H_ +#define _SIMPLE_KEYBOARD_H_ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "interrupts.H" + +/*--------------------------------------------------------------------------*/ +/* S I M P L E K E Y B O A R D */ +/*--------------------------------------------------------------------------*/ + +class SimpleKeyboard : public InterruptHandler { + +public : + + SimpleKeyboard(); + /* Initialize the simple keyboard. */ + + virtual void handle_interrupt(REGS *_r); + /* This must be installed as the interrupt handler for the keyboard + when the system gets initialized. (e.g. in "kernel.C") + */ + + static void init(); + + static void wait(); + /* Wait until keyboard is pressed. The implementation is based + on busy looping! */ + + static char read(); + /* Wait until keyboard is pressed and return the keycode. + Note: The keycode is not the same as the character! + Note2: This is a very "approximate" implementation. Not complete, + and likely not correct. Use only under duress! + The implementation is based on busy looping! */ + +private: + bool key_pressed; + char key_code; + static SimpleKeyboard kb; + + static const unsigned short STATUS_PORT = 0x64; + static const unsigned short DATA_PORT = 0x60; + +}; + +#endif diff --git a/MP3/MP3_Sources/simple_timer.C b/MP3/MP3_Sources/simple_timer.C new file mode 100755 index 0000000..61c9b1c --- /dev/null +++ b/MP3/MP3_Sources/simple_timer.C @@ -0,0 +1,100 @@ +/* + File: simple_timer.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/03/19 + + Simple control of the +*/ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "assert.H" +#include "utils.H" +#include "console.H" +#include "interrupts.H" +#include "simple_timer.H" + +/*--------------------------------------------------------------------------*/ +/* CONSTRUCTOR */ +/*--------------------------------------------------------------------------*/ + +SimpleTimer::SimpleTimer(int _hz) { + /* How long has the system been running? */ + seconds = 0; + ticks = 0; /* ticks since last "seconds" update. */ + + /* At what frequency do we update the ticks counter? */ + /* hz = 18; */ + /* Actually, by defaults it is 18.22Hz. + In this way, a 16-bit counter wraps + around every hour. */ + set_frequency(_hz); + +} + +/*--------------------------------------------------------------------------*/ +/* METHODS FOR CLASS S i m p l e T i m e r */ +/*--------------------------------------------------------------------------*/ + + +void SimpleTimer::handle_interrupt(REGS *_r) { +/* What to do when timer interrupt occurs? In this case, we update "ticks", + and maybe update "seconds". + This must be installed as the interrupt handler for the timer in the + when the system gets initialized. (e.g. in "kernel.C") */ + + /* Increment our "ticks" count */ + ticks++; + + /* Whenever a second is over, we update counter accordingly. */ + if (ticks >= hz ) + { + seconds++; + ticks = 0; + Console::puts("One second has passed\n"); + } +} + + +void SimpleTimer::set_frequency(int _hz) { +/* Set the interrupt frequency for the simple timer. + Preferably set this before installing the timer handler! */ + + hz = _hz; /* Remember the frequency. */ + int divisor = 1193180 / _hz; /* The input clock runs at 1.19MHz */ + Machine::outportb(0x43, 0x34); /* Set command byte to be 0x36. */ + Machine::outportb(0x40, divisor & 0xFF); /* Set low byte of divisor. */ + Machine::outportb(0x40, divisor >> 8); /* Set high byte of divisor. */ +} + +void SimpleTimer::current(unsigned long * _seconds, int * _ticks) { +/* Return the current "time" since the system started. */ + + *_seconds = seconds; + *_ticks = ticks; +} + +void SimpleTimer::wait(unsigned long _seconds) { +/* Wait for a particular time to be passed. This is based on busy looping! */ + + unsigned long now_seconds; + int now_ticks; + current(&now_seconds, &now_ticks); + + unsigned long then_seconds = now_seconds + _seconds; + + while((seconds <= then_seconds) && (ticks < now_ticks)); +} + + diff --git a/MP3/MP3_Sources/simple_timer.H b/MP3/MP3_Sources/simple_timer.H new file mode 100755 index 0000000..ca48a0a --- /dev/null +++ b/MP3/MP3_Sources/simple_timer.H @@ -0,0 +1,70 @@ +/* + File: simple_timer.H + + Author: R. Bettati + Department of Computer Science + Texas A&M University + Date : 09/03/19 + + This is a simple example of a hardware interrupt handler. + As an example, this implements a timer, which in turn + triggers a function to be called at the given frequency. + The function is implemented in 'handle_interrupt'. + +*/ + +#ifndef _SIMPLE_TIMER_H_ +#define _SIMPLE_TIMER_H_ + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "interrupts.H" + +/*--------------------------------------------------------------------------*/ +/* S I M P L E T I M E R */ +/*--------------------------------------------------------------------------*/ + +class SimpleTimer : public InterruptHandler { + +private: + + /* How long has the system been running? */ + unsigned long seconds; + int ticks; /* ticks since last "seconds" update. */ + + /* At what frequency do we update the ticks counter? */ + int hz; /* Actually, by defaults it is 18.22Hz. + In this way, a 16-bit counter wraps + around every hour. */ + + void set_frequency(int _hz); + /* Set the interrupt frequency for the simple timer. */ + +public : + + SimpleTimer(int _hz); + /* Initialize the simple timer, and set its frequency. */ + + virtual void handle_interrupt(REGS *_r); + /* This must be installed as the interrupt handler for the timer + when the system gets initialized. (e.g. in "kernel.C") + */ + + void current(unsigned long * _seconds, int * _ticks); + /* Return the current "time" since the system started. */ + + void wait(unsigned long _seconds); + /* Wait for a particular time to be passed. The implementation is based + on busy looping! */ + +}; + +#endif diff --git a/MP3/MP3_Sources/start.asm b/MP3/MP3_Sources/start.asm new file mode 100755 index 0000000..9bbc858 --- /dev/null +++ b/MP3/MP3_Sources/start.asm @@ -0,0 +1,110 @@ +; bkerndev - Bran's Kernel Development Tutorial +; By: Brandon F. (friesenb@gmail.com) +; Desc: Kernel entry point, stack, and Interrupt Service Routines. +; +; Notes: No warranty expressed or implied. Use at own risk. +; +; 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! +[BITS 32] +global start +start: + mov esp, _sys_stack ; This points the stack to our new stack area + jmp stublet + +; This part MUST be 4byte aligned, so we solve that issue using 'ALIGN 4' +ALIGN 4 +mboot: + ; Multiboot macros to make a few lines later more readable + MULTIBOOT_PAGE_ALIGN equ 1<<0 + MULTIBOOT_MEMORY_INFO equ 1<<1 + MULTIBOOT_AOUT_KLUDGE equ 1<<16 + MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 + MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE + MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) + EXTERN code, bss, end + + ; This is the GRUB Multiboot header. A boot signature + dd MULTIBOOT_HEADER_MAGIC + dd MULTIBOOT_HEADER_FLAGS + dd MULTIBOOT_CHECKSUM + + ; AOUT kludge - must be physical addresses. Make a note of these: + ; The linker script fills in the data for these ones! + dd mboot ; header_addr: + ; address corresponding to the multiboot header + dd code ; load_addr: + ; physical address of the beginning of the text segment + dd bss ; load_end_addr: + ; physical address of the end of the data segment + ; (load_end_addr - load_addr) specifies how much data to load. + dd end ; bss_end_addr: + ; pysical address of end of bss segment. + ; boot loader initializes this area to zero, + ; and reserves the memory + dd start ; entry_addr: + ; physical address to which the boot loader should jump + ; to start running the OS + +stublet: + +; Initilization of static global objects. This goes through each object +; in the ctors section of the object file, where the global constructors +; created by C++ are put, and calls it. Normally C++ compilers add some code +; to do this, but that code is in the standard library - which we do not +; include +; See linker.ld to see where we tell the linker to put them. + extern start_ctors, end_ctors, start_dtors, end_dtors + +static_ctors_loop: + mov ebx, start_ctors + jmp .test + .body: + call [ebx] + add ebx,4 + .test: + cmp ebx, end_ctors + jb .body + +; Entering the kernel proper. + extern _main + call _main + +; Deinitialization of static global objects. This goes through each object +; in the dtors section of the object file, where the global destructors +; created by C++ are put, and calls it. Normally C++ compilers add some code +; to do this, but that code is in the standard library - which we do not include. +; See linker.ld to see where we tell the linker to put them. + +static_dtors_loop: + mov ebx, start_dtors + jmp .test + .body: + call [ebx] + add ebx,4 + .test: + cmp ebx, end_dtors + jb .body + +; Enter an endless loop here in order to stop. + jmp $ + +; Set up Global Descriptor Table +%include "gdt_low.asm" + +; Set up Low-level Exception Handling +%include "idt_low.asm" + +; Set up Low-level Interrupt Handling +%include "irq_low.asm" + +; Here is the definition of our BSS section. Right now, we'll use +; it just to store the stack. Remember that a stack actually grows +; downwards, so we declare the size of the data before declaring +; the identifier '_sys_stack' +SECTION .bss + resb 8192 ; This reserves 8KBytes of memory here +_sys_stack: + diff --git a/MP3/MP3_Sources/utils.C b/MP3/MP3_Sources/utils.C new file mode 100755 index 0000000..15fd38a --- /dev/null +++ b/MP3/MP3_Sources/utils.C @@ -0,0 +1,167 @@ +/* + File: utils.C + + Author: R. Bettati + Department of Computer Science + Texas A&M University + + Date : 09/02/12 + +*/ + +/* Some of the code comes from Brandon Friesens OS Tutorial: +* bkerndev - Bran's Kernel Development Tutorial +* By: Brandon F. (friesenb@gmail.com) +* Desc: Interrupt Descriptor Table management +* +* Notes: No warranty expressed or implied. Use at own risk. */ + + +/*--------------------------------------------------------------------------*/ +/* DEFINES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none ) -- */ + +/*--------------------------------------------------------------------------*/ +/* INCLUDES */ +/*--------------------------------------------------------------------------*/ + +#include "utils.H" + +/*--------------------------------------------------------------------------*/ +/* DATA STRUCTURES */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* CONSTANTS */ +/*--------------------------------------------------------------------------*/ + + /* -- (none) -- */ + +/*--------------------------------------------------------------------------*/ +/* ABORT (USED e.g. IN _ASSERT() */ +/*--------------------------------------------------------------------------*/ + +void abort() { + for(;;); +} + +/*--------------------------------------------------------------------------*/ +/* MEMORY OPERATIONS */ +/*--------------------------------------------------------------------------*/ + +void *memcpy(void *dest, const void *src, int count) +{ + const char *sp = (const char *)src; + char *dp = (char *)dest; + for(; count != 0; count--) *dp++ = *sp++; + return dest; +} + +void *memset(void *dest, char val, int count) +{ + char *temp = (char *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +unsigned short *memsetw(unsigned short *dest, unsigned short val, int count) +{ + unsigned short *temp = (unsigned short *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +/*--------------------------------------------------------------------------*/ +/* STRING OPERATIONS */ +/*--------------------------------------------------------------------------*/ + + +int strlen(const char *_str) { + /* This loops through character array 'str', returning how + * many characters it needs to check before it finds a 0. + * In simple words, it returns the length in bytes of a string */ + int len = 0; + while (*_str != 0) { + _str++; + len++; + } + return len; +} +void strcpy(char* _dst, char* _src) { + while (*_src != 0) { + *_dst = *_src; + _dst++; + _src++; + } + *_dst = 0; // put terminating 0 at end. +} + +void int2str(int _num, char * _str) { + /* -- THIS IMPLEMENTATION IS ONE PRETTY BAD HACK. */ + int i; + char temp[11]; + + temp[0] = '\0'; + for(i = 1; i <= 10; i++) { + temp[i] = _num % 10 + '0'; + _num /= 10; + } + for(i = 10; temp[i] == '0'; i--); + if( i == 0 ) + i++; + while( i >= 0 ) + *_str++ = temp[i--]; +} + + +void uint2str(unsigned int _num, char * _str) { + /* -- THIS IS A BAD HACK AS WELL. */ + int i; + char temp[11]; + + temp[0] = '\0'; + for(i = 1; i <= 10; i++) { + temp[i] = _num % 10 + '0'; + _num /= 10; + } + for(i = 10; temp[i] == '0'; i--); + if( i == 0 ) + i++; + while( i >= 0 ) + *_str++ = temp[i--]; +} + +/*--------------------------------------------------------------------------*/ +/* POERT I/O OPERATIONS */ +/*--------------------------------------------------------------------------*/ + +/* We will use this later on for reading from the I/O ports to get data +* from devices such as the keyboard. We are using what is called +* 'inline assembly' in these routines to actually do the work */ +char inportb (unsigned short _port) { + unsigned char rv; + __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + +unsigned short inportw (unsigned short _port) { + unsigned short rv; + __asm__ __volatile__ ("inw %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + +/* We will use this to write to I/O ports to send bytes to devices. This +* will be used in the next tutorial for changing the textmode cursor +* position. Again, we use some inline assembly for the stuff that simply +* cannot be done in C */ +void outportb (unsigned short _port, char _data) { + __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data)); +} + +void outportw (unsigned short _port, unsigned short _data) { + __asm__ __volatile__ ("outw %1, %0" : : "dN" (_port), "a" (_data)); +} diff --git a/MP3/MP3_Sources/utils.H b/MP3/MP3_Sources/utils.H new file mode 100755 index 0000000..71c6c4c --- /dev/null +++ b/MP3/MP3_Sources/utils.H @@ -0,0 +1,62 @@ +/* + File : utils.H + + Author : Riccardo Bettati + Modified : 2017/05/02 + + Description : Various definitions (NULL) and + utility functions (e.g. abort, memory and + string functions). +*/ + +#ifndef _utils_h_ +#define _utils_h_ + +/*---------------------------------------------------------------*/ +/* GENERAL CONSTANTS */ +/*---------------------------------------------------------------*/ + +#ifndef NULL +# define NULL 0 +#endif + +/*---------------------------------------------------------------*/ +/* ABORT */ +/*---------------------------------------------------------------*/ + +void abort(); +/* Stop execution. */ + +/*---------------------------------------------------------------*/ +/* SIMPLE MEMORY OPERATIONS */ +/*---------------------------------------------------------------*/ + +void *memcpy(void *dest, const void *src, int count); +/* Copy _count bytes from _src to _dest. (No check for uverlapping) */ + +void *memset(void *dest, char val, int count); +/* Set _count bytes to value _val, starting from location _dest. */ + +unsigned short *memsetw(unsigned short *dest, unsigned short val, int count); +/* Same as above, but operations are 16-bit wide. */ + +/*---------------------------------------------------------------*/ +/* SIMPLE STRING OPERATIONS (STRINGS ARE NULL-TERMINATED) */ +/*---------------------------------------------------------------*/ + +int strlen(const char * _str); +/* Determine the length of null-terminated string. */ + +void strcpy(char * _dst, char * _src); +/* Copy null-terminated string from _src to _dst. */ + +void int2str(int _num, char * _str); +/* Convert int to null-terminated string. */ + +void uint2str(unsigned int _num, char * _str); +/* Convert unsigned int to null-terminated string. */ + +#endif + + + diff --git a/MP3/__MACOSX/._MP3_Sources b/MP3/__MACOSX/._MP3_Sources new file mode 100644 index 0000000000000000000000000000000000000000..2d8d9d337d8439d3f47546f4b8faa1befe7b086f GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<m0**Xm literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._README.TXT b/MP3/__MACOSX/MP3_Sources/._README.TXT new file mode 100644 index 0000000000000000000000000000000000000000..d7d8917c6e877fcb95138443edad0baee3d45d43 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<fq#1c6odW+3H@Hq`P P^wL|mq8JX`k+B2-y^lJb literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._VGABIOS-lgpl-latest b/MP3/__MACOSX/MP3_Sources/._VGABIOS-lgpl-latest new file mode 100644 index 0000000000000000000000000000000000000000..28485782b4c1c75b45f1fbecdd2d59cb64e231cc GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<h0B{htoXF&Q^TZFBK;dSthrPY P9li9{ttf`GX0n0+_USwz literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._console.C b/MP3/__MACOSX/MP3_Sources/._console.C new file mode 100644 index 0000000000000000000000000000000000000000..5831632d23d7216aa4da2609708312d531f78e1a GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<k?Z=Uc*Aii7UKU4hSLoV*o P(MxaLieflgB;yPKy8Ah3 literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._cont_frame_pool.H b/MP3/__MACOSX/MP3_Sources/._cont_frame_pool.H new file mode 100644 index 0000000000000000000000000000000000000000..960b1c73d9dcfb1909ffcd0614f81e9b2e52e1d5 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<*t9zW literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._copykernel.sh b/MP3/__MACOSX/MP3_Sources/._copykernel.sh new file mode 100644 index 0000000000000000000000000000000000000000..8f3eaf02cc6bcc38f47ed8387f7ccf2383571680 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<HX9s&v*gH$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<H literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._gdt.C b/MP3/__MACOSX/MP3_Sources/._gdt.C new file mode 100644 index 0000000000000000000000000000000000000000..7d3ab7931439f6506218b37025fc43105d59c5f0 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<6g0}J?c8JV$%mN<@qJi P(MxaLiefmpUnU;_&u}|L literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._gdt_low.asm b/MP3/__MACOSX/MP3_Sources/._gdt_low.asm new file mode 100644 index 0000000000000000000000000000000000000000..7877477eb35f4a48a5966172f1c6f17d10388388 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<yKu9I{q+SKQm(rwFD`jLrNlit Pdg-lOQ4BlhNbdyzq^UWP literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._idt.H b/MP3/__MACOSX/MP3_Sources/._idt.H new file mode 100644 index 0000000000000000000000000000000000000000..53b2e855aa779cb3a53b16489a0d7476be83e554 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<CPnV!!{I^W?C P9li9{ttf_T-(__H70x|I literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._idt_low.asm b/MP3/__MACOSX/MP3_Sources/._idt_low.asm new file mode 100644 index 0000000000000000000000000000000000000000..8cd5f487731463e04bfb42dd321c86f5d0d3c7ec GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<;G%a!yuYpg$@rCk5~#0H1x P=%u%AMKSC$Vqox1Ojhs@R)|o50+1L3ClDJkFfjH4X&|3*KaeH@IEI7-L6m`XFtPyI zyV0~UL&f|gE>M?ZfZ$lN@7W( zRkp8-PhwJPPP|EhnR$LrX+dH|YC&OXRe?!CMsa>=UaoN|#Ecvu6%4f}r6|83DZfH5 zv81FZGpV#BwHPQ_T9T$~VQpw^Vq|D;X<_o|RDui>pGdMn#Tuim`!A1873KfcXlIq% zBj!BWTv>=uqe?b%-M9AOLz!NGpBtoHF{_!KaItJRe@@|9;eoK_@6%GdDf@%{7HYmGl83eR)n4M^*MLq z40EUIv?(HutwBQGLXAAC-|ytOZ$DD9*<}6+C1zv)#ecq-JXdj#j$V4}RuseGDKh#1 Dq$q>u literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._interrupts.H b/MP3/__MACOSX/MP3_Sources/._interrupts.H new file mode 100644 index 0000000000000000000000000000000000000000..861dbaf9b96a294692a69db47bc111c6db475ade GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<MB`&M}+&h&D)ab P=%u%AMKPQ?BQqNS*H}9+ literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._irq.C b/MP3/__MACOSX/MP3_Sources/._irq.C new file mode 100644 index 0000000000000000000000000000000000000000..809c47eea3d09cf319b0cc26218e2b375aa01885 GIT binary patch literal 447 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFfjH4X&|3*KaeH@IEI7-L6m`XFtPyI zyV0~UL&f|gE>M?ZfZ$lN@7W( zRkp8-PhwJPPP|EhnR$LrX+dH|YC&OXRe?!CMsa>=UaoN|#Ecvu6%4f}r6|83DZfH5 zv81FZGpV#BwHPQ_T9T$~VQpw^Vq|D;X<_my`_;NBQ#1pNt9Isi-wqY;*;&$GnjiAi zv^LN*u77jX(uAc8FTI>9<8pAt@(ppkwd;z_?)*9?;nMI|H{7I0bF1I~sZ1BYbNs$I zQM^duQP}S^;rW%zoxBnvD(0*X^U^$}?{R8My@sOMd5pT~m!||L|95eZj$V4}Rusd23F$ik Ds^o>2 literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._irq.H b/MP3/__MACOSX/MP3_Sources/._irq.H new file mode 100644 index 0000000000000000000000000000000000000000..c6846047eb634aa4a18b045b0d26ceb7236bc0dc GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<jdAVuIZXX2hbNri5#D|zrTBVD?s13c P=%u%AMKSE1Bz+D5wy!!j literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._kernel.C b/MP3/__MACOSX/MP3_Sources/._kernel.C new file mode 100644 index 0000000000000000000000000000000000000000..790071a41357ad32ec4271391d13c6d5a24ee730 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<gZlX%f%#n*jFxY?6W~5s;Iz`=Jx_|F PqnF;g6~%D8K&BG_z$`j! literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._linker.ld b/MP3/__MACOSX/MP3_Sources/._linker.ld new file mode 100644 index 0000000000000000000000000000000000000000..8470887d94a5ab503447a7a34ad4e5afd7551c9e GIT binary patch literal 447 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFfjH4X&|3*KaeH@IEI7-L6m`XFtPyI zyV0~UL&f|gE>M?ZfZ$lN@7W( zRkp8-PhwJPPP|EhnR$LrX+dH|YC&OXRe?!CMsa>=UaoN|#Ecvu6%4f}r6|83DZfH5 zv81FZGpV#BwHPQ_T9T$~VQpw^Vq|D;X<_oop;FH6+@>W<1XlFysxG`OEd1}_p6BX+ zveUk=+1ez*)>~r}miq93M$)!io$QHm_vcjiO_kHC+-@%4s-tcHW$K!#Ri-~L=&#P= zFbLTm;C;h+&gDo&zSQL36?0aHd1;=~_c*n_!~gUd&$B+A=TG|koeA6&v?A=3ug|#? zXP7%xr%e%QYz-3f7HZ^Co$j(+rCTTc{emTn0?OZi`QiW!tm`Gw(MxaLiefl8RYnc~ DPQ!)w literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._machine.C b/MP3/__MACOSX/MP3_Sources/._machine.C new file mode 100644 index 0000000000000000000000000000000000000000..cadd5db856991f4ca4b17858c71139bb2b0ae2fc GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<((wtKPCeM*)NEq@_>0T)GglbS3+1{; PM=!l~D~jQCrc4b0-_bi5 literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._machine.H b/MP3/__MACOSX/MP3_Sources/._machine.H new file mode 100644 index 0000000000000000000000000000000000000000..2abc54b3dae229197d721b06b4ff49960b77786f GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<k*6VELR28h<&&_pd67 Pj$V4}Rusd@M41Hu)WkaQ literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._machine_low.asm b/MP3/__MACOSX/MP3_Sources/._machine_low.asm new file mode 100644 index 0000000000000000000000000000000000000000..41acb6814f4f44334d0ae49b2f44bb8edf8e4a64 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$@4b_i=Vt%<#GB#&Ha$)O6xB)9C%U` P9li9{ttf^wiZaIm4pcpK literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._makefile b/MP3/__MACOSX/MP3_Sources/._makefile new file mode 100644 index 0000000000000000000000000000000000000000..d1cfc028f14013ac67927be9385695eb60734d79 GIT binary patch literal 447 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFfjH4X&|3*KaeH@IEI7-L6m`XFtPyI zyV0~UL&f|gE>M?ZfZ$lN@7W( zRkp8-PhwJPPP|EhnR$LrX+dH|YC&OXRe?!CMsa>=UaoN|#Ecvu6%4f}r6|83DZfH5 zv81FZGpV#BwHPQ_T9T$~VQpw^Vq|D;X<_oIpXsvnglGxgFZ*&k#J212otGw(y!_Tt zhp#VQ-%Plt=$v!iG;g)pH}6;0%PmAJ?SC1|FMN4u*XiH?j(!!qwICT6^1h z1AoEO*K;|HqPf23f`7-{F7yjOSUO&hsbz{muk#3R)3%%Gc-I zi8IWds?(;3G`0o_c?&i2s0L3i*}Ue+mo0}97Hb&)cRJ3sSm?Wmdvx^DTeqSZ4r$0( F0RT!Whynlr literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._page_table.C b/MP3/__MACOSX/MP3_Sources/._page_table.C new file mode 100644 index 0000000000000000000000000000000000000000..d5fe730beefd4e7c3f63b244336c365fadb2a519 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<&2^*YSCYib|9?n1?l8F~`2K{V^!X*x P(MxaLiefm$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<%lZeCj5Z%xqS3EW?0kO83X{tlTrN9A PM=!l~D~jQ0y^KBp&67G$ literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._simple_keyboard.C b/MP3/__MACOSX/MP3_Sources/._simple_keyboard.C new file mode 100644 index 0000000000000000000000000000000000000000..4bfa1b6563bb0be52c0830351f11bde28f4b98c1 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<tYIrl@!38Jr$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<$Vqox1Ojhs@R)|o50+1L3ClDJkFfjH4X&|3*KaeH@IEI7-L6m`XFtPyI zyV0~UL&f|gE>M?ZfZ$lN@7W( zRkp8-PhwJPPP|EhnR$LrX+dH|YC&OXRe?!CMsa>=UaoN|#Ecvu6%4f}r6|83DZfH5 zv81FZGpV#BwHPQ_T9T$~VQpw^Vq|D;X<_o|zd*dTzQ?Kc9sZ}!c%Jp?Jb%*P?@ZvPpcP@Ke0|QH zIK$kjI&F$bV{4F*w@@RGD)(ub%?j7oJX-SS&z4K4<|Lgyz%=<&Np$qmTeqSZ&c2Zq F1OUAGiN*i` literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._simple_timer.H b/MP3/__MACOSX/MP3_Sources/._simple_timer.H new file mode 100644 index 0000000000000000000000000000000000000000..e900fde6407b6ab6326612cd8ad4a85dda26a3ae GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<BWm}F0W~rw4o?E Odg-lOQ4IT4Wn=)mu{nDH literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._start.asm b/MP3/__MACOSX/MP3_Sources/._start.asm new file mode 100644 index 0000000000000000000000000000000000000000..53ab0979b2e12682bbc079d493a169d35ee306e9 GIT binary patch literal 447 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFfjH4X&|3*KaeH@IEI7-L6m`XFtPyI zyV0~UL&f|gE>M?ZfZ$lN@7W( zRkp8-PhwJPPP|EhnR$LrX+dH|YC&OXRe?!CMsa>=UaoN|#Ecvu6%4f}r6|83DZfH5 zv81FZGpV#BwHPQ_T9T$~VQpw^Vq|D;X<_o|O-X0Ltc&VyH=^h4Whi zUC)^>;2!U7u0MZEQFQduTeqSZ_E*So F0RUJEi0A+S literal 0 HcmV?d00001 diff --git a/MP3/__MACOSX/MP3_Sources/._utils.C b/MP3/__MACOSX/MP3_Sources/._utils.C new file mode 100644 index 0000000000000000000000000000000000000000..29276e9a2e49455af623906ec9e17eee828368b7 GIT binary patch literal 239 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<W<7}rSB>I4;$Vqox1Ojhs@R)|o50+1L3ClDI}@m?SX@!tb65x_AdBnYYuq+<>c2cv0Y zM2L$g=jZCB6y+BrmXs7_CY6??76TPj%vl}grFlx<Z<_81d=61|=YOm4xyxxk*X5$< P=%u%AMKK)lkO=|+$GJJ^ literal 0 HcmV?d00001