1

add vorgabe08

This commit is contained in:
2022-06-23 13:08:36 +02:00
parent e6e2674164
commit ceb17dd2c1
6 changed files with 702 additions and 6 deletions

212
c_os/kernel/Paging.cc Normal file
View File

@ -0,0 +1,212 @@
/*****************************************************************************
* *
* P A G I N G *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Rudimentaeres Paging: 1:1 Mapping fuer gesamten logischen*
* Adressraum. logische Adresse = physikalische Adresse *
* *
* Page-Directory (alle Eintraege present, read/write *
* 0. Eintrag zeigt auf eine Page-Table (4 KB Eintraege)*
* Alle restl. Eintraege sind 4 MB Seiten und verweisen *
* somit auf keine Page-Tabelle sondern direkt auf die *
* 4 MB Seite. *
* *
* Page-Table (Logische Adressen 0 - 4 MB) *
* 1. Eintrag not present, read-only *
* -> Null-Pointer abfangen *
* 2. restl. Eintraege present & read/write *
* *
* Memory-Laylout *
* *
* boot.asm *
* 0x07c0: Bootsector vom BIOS geladen *
* 0x0060: Boot-Code verschiebt sich hier hin *
* 0x9000: Setup-Code (max. 64K inkl. Stack) vom *
* Bootsector-Code geladen *
* setup.asm *
* 0x1000: System-Code (max. 512K) geladen *
* BIOS-Aufruf *
* 0x24000: Parameter fuer BIOS-Aufurf *
* 0x25000: Altes ESP sichern, vor BIOS-Aufruf *
* 0x26000: 16-Bit Code-Segment fuer BIOS-Aufurf *
* System-Code *
* 0x100000: System-Code, kopiert nach Umschalten in *
* den Protected Mode kopiert (GRUB kann nur *
* an Adressen >1M laden) *
* Globale Variablen: Direkt nach dem Code liegen die globalen *
* Variablen. *
* Paging: *
* 0x200000: Page-Directory *
* 0x201000: Page-Table *
* 0x202000: erste allozierbare Page (via Paging.cc) *
* 0x3FF000: Anfang der letzten allozierbaren Page *
* Heap: *
* 0x400000: Start-Adresse der Heap-Verwaltung *
* Ende: Letzte Adresse des phys. Speichers *
* *
* *
* Autor: Michael Schoettner, 20.12.2018 *
*****************************************************************************/
#include "kernel/Globals.h"
#include "kernel/Paging.h"
// Bits fuer Eintraege in der Page-Table
#define PAGE_PRESENT 0x001
#define PAGE_WRITEABLE 0x002
#define PAGE_BIGSIZE 0x080
#define PAGE_RESERVED 0x800 // Bit 11 ist frei fuer das OS
// Adresse des Page-Directory (benoetigt 4 KB)
#define PAGE_DIRECTORY 0x200000
// Adresse der Page-Table (benoetigt 4 KB)
#define PAGE_TABLE 0x201000
// Start- und End-Adresse der 4 KB Seiten die durch die Page-Table adressiert werden
#define FST_ALLOCABLE_PAGE 0x202000
#define LST_ALLOCABLE_PAGE 0x2FF000
// Externe Funktionen in startup.asm
extern "C" {
void paging_on (unsigned int* p_pdir); // Paging einschalten
void invalidate_tlb_entry(unsigned int* ptr); // Page in TLB invalid.
}
/*****************************************************************************
* Funktion: pg_alloc_page *
*---------------------------------------------------------------------------*
* Beschreibung: Alloziert eine 4 KB Seite. Allozieren heisst hier *
* lediglich Setzen eines eigenen RESERVED-Bits. *
*****************************************************************************/
unsigned int * pg_alloc_page() {
unsigned int *p_page;
p_page = (unsigned int*) PAGE_TABLE;
// 1. Eintrag ist fuer Null-Pointer-Exception reserviert
// ausserdem liegt an die Page-Table an Adresse PAGE_TABLE
// somit ist est PAGE_TABLE + 4 KB frei (bis max. 3 MB, da beginnt der Heap)
for (int i = 1; i < 1024; i++) {
p_page ++;
// pruefe ob Page frei
if ( ((*p_page) & PAGE_RESERVED) == 0) {
*p_page = ( *p_page | PAGE_RESERVED);
return (unsigned int*)(i<<12);
}
}
return 0;
}
/*****************************************************************************
* Funktion: pg_write_protect_page *
*---------------------------------------------------------------------------*
* Beschreibung: Schreibschutz fuer die uebergebene Seite aktivieren. *
* Dies fuer das Debugging nuetzlich. *
*****************************************************************************/
void pg_write_protect_page(unsigned int *p_page) {
/* hier muss Code eingefügt werden */
}
/*****************************************************************************
* Funktion: pg_notpresent_page *
*---------------------------------------------------------------------------*
* Beschreibung: Seite als ausgelagert markieren. Nur fuer Testzwecke. *
*****************************************************************************/
void pg_notpresent_page(unsigned int *p_page) {
/* hier muss Code eingefügt werden */
}
/*****************************************************************************
* Funktion: pg_free_page *
*---------------------------------------------------------------------------*
* Beschreibung: Gibt eine 4 KB Seite frei. Es wird hierbei das RESERVED- *
* Bit geloescht. *
*****************************************************************************/
void pg_free_page(unsigned int *p_page) {
int idx = (unsigned int)p_page >> 12;
// ausserhalb Page ?
if (idx < 1 || idx > 1023) return ;
// Eintrag einlesen und aendern (PAGE_WRITEABLE loeschen)
p_page = (unsigned int*) PAGE_TABLE;
p_page += idx;
*p_page = ((idx << 12) | PAGE_WRITEABLE | PAGE_PRESENT);
}
/*****************************************************************************
* Funktion: pg_init *
*---------------------------------------------------------------------------*
* Beschreibung: Page-Tables einrichten und Paging mithilfe von *
* startup.asm aktivieren. *
*****************************************************************************/
void pg_init() {
unsigned int i;
unsigned int *p_pdir; // Zeiger auf Page-Directory
unsigned int *p_page; // Zeiger auf einzige Page-Table fuer 4 KB Pages
unsigned int num_pages; // Anzahl 4 MB Pages die phys. Adressraum umfassen
// wie viele 4 MB Seiten sollen als 'Present' angelegt werden,
// sodass genau der physikalische Adressraum abgedeckt ist?
num_pages = total_mem/(4096*1024);
kout << "pg_init: " << total_mem << endl;
kout << " total_mem: " << total_mem << endl;
kout << " #pages: " << total_mem/(4096*1024) << endl;
//
// Aufbau des Page-Directory
//
// Eintrag 0: Zeiger auf 4 KB Page-Table
p_pdir = (unsigned int*) PAGE_DIRECTORY;
*p_pdir = PAGE_TABLE | PAGE_WRITEABLE | PAGE_PRESENT;
// Eintraege 1-1023: Direktes Mapping (1:1) auf 4 MB Pages (ohne Page-Table)
for (i = 1; i < 1024; i++) {
p_pdir ++;
if (i>num_pages)
*p_pdir = ( (i<<22) | PAGE_BIGSIZE);
else
*p_pdir = ( (i<<22) | PAGE_BIGSIZE | PAGE_WRITEABLE | PAGE_PRESENT);
}
//
// 1. Page-Table
//
p_page = (unsigned int*) PAGE_TABLE;
// ersten Eintrag loeschen -> not present, write protected -> Null-Pointer abfangen
*p_page = 0;
// Eintraege 1-1023: Direktes Mapping (1:1) auf 4 KB page frames
for (i = 1; i < 1024; i++) {
p_page ++;
// Seiten unter FST_ALLOCABLE_PAGE reservieren, damit diese nicht
// alloziert werden und das System kaputt geht
if ( (i<<12) >= FST_ALLOCABLE_PAGE)
*p_page = ((i << 12) | PAGE_WRITEABLE | PAGE_PRESENT);
else
*p_page = ((i << 12) | PAGE_WRITEABLE | PAGE_PRESENT | PAGE_RESERVED);
}
// Paging aktivieren (in startup.asm)
paging_on( (unsigned int*) PAGE_DIRECTORY );
}

72
c_os/kernel/Paging.h Normal file
View File

@ -0,0 +1,72 @@
/*****************************************************************************
* *
* P A G I N G *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Rudimentaeres Paging: 1:1 Mapping fuer gesamten logischen*
* Adressraum. logische Adresse = physikalische Adresse *
* *
* Page-Directory (alle Eintraege present, read/write *
* 0. Eintrag zeigt auf eine Page-Table (4 KB Eintraege)*
* Alle restl. Eintraege sind 4 MB Seiten und verweisen *
* somit auf keine Page-Tabelle sondern direkt auf die *
* 4 MB Seite. *
* *
* Page-Table (Logische Adressen 0 - 4 MB) *
* 1. Eintrag not present, read-only *
* -> Null-Pointer abfangen *
* 2. restl. Eintraege present & read/write *
* *
* Memory-Laylout *
* *
* boot.asm *
* 0x07c0: Bootsector vom BIOS geladen *
* 0x0060: Boot-Code verschiebt sich hier hin *
* 0x9000: Setup-Code (max. 64K inkl. Stack) vom *
* Bootsector-Code geladen *
* setup.asm *
* 0x1000: System-Code (max. 512K) geladen *
* BIOS-Aufruf *
* 0x24000: Parameter fuer BIOS-Aufurf *
* 0x25000: Altes ESP sichern, vor BIOS-Aufruf *
* 0x26000: 16-Bit Code-Segment fuer BIOS-Aufurf *
* System-Code *
* 0x100000: System-Code, kopiert nach Umschalten in *
* den Protected Mode kopiert (GRUB kann nur *
* an Adressen >1M laden) *
* Globale Variablen: Direkt nach dem Code liegen die globalen *
* Variablen. *
* Paging: *
* 0x200000: Page-Directory *
* 0x201000: Page-Table *
* 0x202000: erste allozierbare Page (via Paging.cc) *
* 0x3FF000: letzte allozierbare Page *
* Heap: *
* 0x400000: Start-Adresse der Heap-Verwaltung *
* Ende: Letzte Adresse des phys. Speichers *
* *
* *
* Autor: Michael Schoettner, 2.2.2017 *
*****************************************************************************/
#ifndef __Paging_include__
#define __Paging_include__
// ativiert paging
extern void pg_init();
// alloziert eine 4 KB Page
extern unsigned int * pg_alloc_page();
// Schreibschutz auf Seite setzen -> fuer debugging nuetzlich
extern void pg_write_protect_page(unsigned int *p_page);
// Present Bit loeschen
extern void pg_notpresent_page(unsigned int *p_page);
// gibt eine 4 KB Page frei
extern void pg_free_page(unsigned int *p_page);
#endif

View File

@ -0,0 +1,316 @@
/*****************************************************************************
* *
* B L U E S C R E E N *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
* kout etc. verwendet wird. *
* *
* Autor: Michael Schoettner, 11.12.2018 *
*****************************************************************************/
#include "kernel/Globals.h"
#include "devices/CGA.h"
// in startup.asm
extern "C" {
// CR2 auslesen
unsigned int get_page_fault_address();
// 1st level interrupt handler in startup.asm sichert Zeiger auf Stackframe
// unmittelbar nach dem Interrupt und nachdem alle Register mit PUSHAD
// gesichert wurden
// |-------------|
// |  EFLAGS |
// |-------------|
// | CS |
// |-------------|
// | EIP |
// |-------------|
// | [ErrorCode] |
// |-------------|
// | EAX |
// |-------------|
// | ECX |
// |-------------|
// | EDX |
// |-------------|
// | EBX |
// |-------------|
// | ESP |
// |-------------|
// | EBP |
// |-------------|
// | ESI |
// |-------------|
// | EDI |
// |-------------| <-- int_esp
void get_int_esp (unsigned int** esp);
}
void break_on_bluescreen() {
/* wenn auf diese Methode ein breakpoint in GDB gesetzt wird
so kann man sich mithilfe des Hex-Dumps umsehen
*/
}
// Cursor-Position
int bs_xpos = 0;
int bs_ypos = 0;
/*****************************************************************************
* Funktion: bs_clear *
*---------------------------------------------------------------------------*
* Beschreibung: Bildschirm loeschen. *
*****************************************************************************/
void bs_clear() {
unsigned int x,y;
unsigned short *ptr = (unsigned short*)0xb8000;
for (x=0; x<80; x++) {
for (y=0; y<25; y++)
*(ptr + y*80 + x) = (short)0x1F00;
}
bs_xpos = 0;
bs_ypos = 0;
}
/*****************************************************************************
* Funktion: bs_lf *
*---------------------------------------------------------------------------*
* Beschreibung: Zeilenvorschub. *
*****************************************************************************/
void bs_lf() {
bs_ypos++;
bs_xpos=0;
}
/*****************************************************************************
* Funktion: bs_print_char *
*---------------------------------------------------------------------------*
* Beschreibung: Ein Zeichen ausgeben. *
*****************************************************************************/
void bs_print_char(char c) {
unsigned char *ptr = (unsigned char*)0xb8000;
*(ptr + bs_ypos*80*2 + bs_xpos*2) = c;
bs_xpos++;
}
/*****************************************************************************
* Funktion: bs_print_string *
*---------------------------------------------------------------------------*
* Beschreibung: Eine Zeichenkette ausgeben. *
*****************************************************************************/
void bs_print_string(char *str) {
while ( *str != '\0' ) {
bs_print_char( *str );
str++;
}
}
/*****************************************************************************
* Funktion: bs_printHexDigit *
*---------------------------------------------------------------------------*
* Beschreibung: Ein Hex-Zeichen ausgeben. *
*****************************************************************************/
void bs_printHexDigit(int c) {
if (c<10) bs_print_char('0'+(unsigned char)c);
else bs_print_char('A'+(unsigned char)(c-10));
}
/*****************************************************************************
* Funktion: bs_print_uintHex *
*---------------------------------------------------------------------------*
* Beschreibung: Integer ausgeben. *
*****************************************************************************/
void bs_print_uintHex(unsigned int c) {
for (int i=28; i>=0; i=i-4) {
bs_printHexDigit( (c>>i)&0xF );
}
}
/*****************************************************************************
* Funktion: bs_printReg *
*---------------------------------------------------------------------------*
* Beschreibung: String mit Integer ausgeben. Wird verwendet um ein *
* Register auszugeben. *
*****************************************************************************/
void bs_printReg(char *str, int value) {
bs_print_string(str);
bs_print_uintHex(value);
bs_print_string(" \0");
}
/*****************************************************************************
* Funktion: bs_dump *
*---------------------------------------------------------------------------*
* Beschreibung: Hauptroutine des Bluescreens. *
*****************************************************************************/
void bs_dump (unsigned int exceptionNr) {
unsigned int *int_esp;
unsigned int *sptr;
unsigned int faultAdress;
unsigned int has_error_code = 0;
bs_clear ();
bs_print_string("HHUos crashed with Exception\0");
// Exception mit Error-Code?
if ( (exceptionNr>=8 && exceptionNr<=14) || exceptionNr==17 || exceptionNr==30)
has_error_code = 1;
// Liegt ein Page-Fault vor?
if (exceptionNr==14) {
faultAdress = get_page_fault_address();
// Zugriff auf Seite 0 ? -> Null-Ptr. Exception
if ((faultAdress & 0xFFFFF000) == 0)
exceptionNr=0x1B;
}
bs_print_uintHex(exceptionNr);
bs_print_string(" (\0");
// Spruch ausgeben
switch (exceptionNr) {
case 0x00: bs_print_string("Divide Error\0"); break;
case 0x01: bs_print_string("Debug Exception\0"); break;
case 0x02: bs_print_string("NMI\0"); break;
case 0x03: bs_print_string("Breakpoint Exception\0"); break;
case 0x04: bs_print_string("Into Exception\0"); break;
case 0x05: bs_print_string("Index out of range Exception\0"); break;
case 0x06: bs_print_string("Invalid Opcode\0"); break;
case 0x08: bs_print_string("Double Fault\0"); break;
case 0x0D: bs_print_string("General Protection Error\0"); break;
case 0x0E: bs_print_string("Page Fault\0"); break;
case 0x18: bs_print_string("Stack invalid\0"); break;
case 0x19: bs_print_string("Return missing\0"); break;
case 0x1A: bs_print_string("Type Test Failed\0"); break;
case 0x1B: bs_print_string("Null pointer exception\0"); break;
case 0x1C: bs_print_string("MAGIC.StackTest failed\0"); break;
case 0x1D: bs_print_string("Memory-Panic\0"); break;
case 0x1E: bs_print_string("Pageload failed\0"); break;
case 0x1F: bs_print_string("Stack overflow\0"); break;
default: bs_print_string("unknown\0");
}
bs_print_string(")\0"); bs_lf();
// Zeiger auf int_esp ueber startup.asm beschaffen (Stack-Layout siehe Anfang dieser Datei)
get_int_esp (&int_esp);
// wir müssen den Inhalt auslesen und das als Zeiger verwenden, um den Stack auszulesen
sptr = (unsigned int*) *int_esp;
bs_lf();
// wichtigste Register ausgeben
// Exception mit Error-Code?
bs_printReg("EIP=\0", *(sptr + 8 + has_error_code) );
bs_printReg("EBP=\0", *(sptr + 2) );
bs_printReg("ESP=\0", *(sptr + 3) );
bs_printReg(" CS=\0", *(sptr + 9 + has_error_code) );
bs_lf();
// verbleibende nicht-fluechtige Register ausgeben
bs_printReg("EBX=\0", *(sptr + 4) );
bs_printReg("ESI=\0", *(sptr + 1) );
bs_printReg("EDI=\0", *(sptr) );
bs_lf();
// verbleibende fluechtige Register ausgeben
bs_printReg("EDX=\0", *(sptr + 5) );
bs_printReg("ECX=\0", *(sptr + 6) );
bs_printReg("EAX=\0", *(sptr + 7) );
bs_printReg("EFL=\0", *(sptr + 10) );
bs_lf();
// Pagefault oder Null-Pointer?
if (exceptionNr==14 || exceptionNr==0x1B) {
bs_lf();
bs_print_string("Fault address = \0");
bs_print_uintHex(faultAdress);
bs_lf();
bs_print_string("Last useable address = \0");
bs_print_uintHex(total_mem-1);
bs_lf();
}
// Exception mit Error-Code?
if ( has_error_code == 1) {
int error_nr = *(sptr + 8);
if (exceptionNr==14) {
if (error_nr==3) {
bs_print_string("Error: write access to read-only page.\0");
}
else if (error_nr==2) {
bs_print_string("Error: read access to not-present page.\0");
}
else if (error_nr==0) {
bs_print_string("Error: access to a not-present page.\0");
}
else {
bs_print_string("Error code = \0");
bs_print_uintHex( error_nr );
}
bs_lf();
}
else {
bs_print_string("Error code = \0");
bs_print_uintHex( error_nr );
bs_lf();
}
}
// Calling stack ...
bs_lf();
bs_print_string("Calling Stack:\0"); bs_lf();
int x = 0;
unsigned int *ebp = (unsigned int *) *(sptr + 2);
unsigned int raddr;
// solange eip > 1 MB && ebp < 128 MB, max. Aufruftiefe 10
while ( *ebp>0x100000 && *ebp<0x8000000 && x<10 ) {
raddr = *(ebp+1);
bs_printReg(" raddr=\0", raddr ); bs_lf();
// dynamische Kette -> zum Aufrufer
ebp = (unsigned int*) *ebp;
x++;
}
if (x==0) {
bs_print_string(" empty\0"); bs_lf();
}
bs_lf();
// nur falls gdb benutzt werden soll
break_on_bluescreen();
bs_print_string("System halted\0");
}

View File

@ -0,0 +1,21 @@
/*****************************************************************************
* *
* B L U E S C R E E N *
* *
*---------------------------------------------------------------------------*
* Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. *
* ist der Stack und oder Heap kaputt, weswegen hier nicht *
* kout etc. verwendet wird. *
* *
* Autor: Michael Schoettner, 2.2.2017 *
*****************************************************************************/
#ifndef __Bluescreen_include__
#define __Bluescreen_include__
// dump blue screen (will not return)
void bs_dump (unsigned int exceptionNr);
#endif

View File

@ -10,9 +10,11 @@
* *
* Autor: Michael Schoettner, 31.8.2016 *
*****************************************************************************/
#include "kernel/interrupts/IntDispatcher.h"
#include "kernel/CPU.h"
#include "kernel/Globals.h"
#include "kernel/interrupts/IntDispatcher.h"
#include "kernel/interrupts/Bluescreen.h"
extern "C" void int_disp(unsigned int slot);
@ -31,11 +33,19 @@ extern "C" void int_disp(unsigned int slot);
void int_disp(unsigned int vector) {
/* hier muss Code eingefuegt werden */
if (vector < 32) {
bs_dump(vector);
cpu.halt ();
}
// kout << "Ein Interrupt ist aufgetreten (vector: " << vector << ")" << endl;
intdis.report(vector);
if (intdis.report (vector) < 0) {
kout << "Panic: unexpected interrupt " << vector;
kout << " - processor halted." << endl;
cpu.halt ();
}
}
/*****************************************************************************
* Konstruktor: IntDispatcher::IntDispatcher *
*---------------------------------------------------------------------------*

71
c_os/startup.asm Executable file → Normal file
View File

@ -9,7 +9,7 @@
;* die weitere Ausfuehrung durch C-Code erfolgen kann. *
;* *
;* Autor: Olaf Spinczyk, TU Dortmund *
;* Michael Schoettner, HHU, 9.9.2016 *
;* Michael Schoettner, HHU, 15.12.2018 *
;******************************************************************************
; Multiboot-Konstanten
@ -31,6 +31,10 @@ MULTIBOOT_EAX_MAGIC equ 0x2badb002
[GLOBAL idt]
[GLOBAL __cxa_pure_virtual]
[GLOBAL bios_call]
[GLOBAL invalidate_tlb_entry]
[GLOBAL paging_on]
[GLOBAL get_page_fault_address]
[GLOBAL get_int_esp]
; Michael Schoettner:
; Nachfolgender label steht fuer das 'delete', welches jetzt implementiert
@ -138,7 +142,9 @@ _fini_done:
%macro wrapper 1
wrapper_%1:
push eax
pushad ; alle Register sichern (fuer den Bluescreen)
mov ecx, int_esp ; Stack_zeiger sichern, fuer Zugriff im Bluescreen
mov [ecx], esp
mov al,%1
jmp wrapper_body
%endmacro
@ -161,7 +167,7 @@ wrapper_body:
add esp,4 ; Parameter vom Stack entfernen
pop edx ; fluechtige Register wieder herstellen
pop ecx
pop eax
popad ; alle Register wiederherstellen
iret ; fertig!
;
@ -252,6 +258,46 @@ bios_call:
lidt [idt_descr]
ret
; Paging aktivieren
; (siehe Paging.cc)
paging_on:
mov eax,[4+esp] ; Parameter Addr. Page-Dir. ins eax Register
mov ebx, cr4
or ebx, 0x10 ; 4 MB Pages aktivieren
mov cr4, ebx ; CR4 schreiben
mov cr3, eax ; Page-Directory laden
mov ebx, cr0
or ebx, 0x80010000 ; Paging aktivieren
mov cr0, ebx
ret
; Paging-Fault-Adresse holen
; (siehe Paging.cc)
get_page_fault_address:
mov eax,cr2
ret
; Invalidiert eine Seite im TLB. Dies notwendig, falls eine
; die Bits Present, R/W in einem Seitentabelleneintrag
; geaendert werden. Falls die Seite im TLB gespeichert ist
; wuerde die MMU nichts von diesen Aenderungen erkennen,
; da die MMU dann nicht auf die Seitentabellen zugreift.
; (siehe Paging.cc)
invalidate_tlb_entry:
mov eax, [esp+4]
invlpg [eax]
ret
; Auslesen von 'int_esp'
; wird im Bluescreen benoetigt, um den Stacks zuzugreifen
;
; C Prototyp: void get_int_esp (unsigned int** esp);
get_int_esp:
mov eax,[4+esp] ; esp
mov ecx, int_esp
mov [eax], ecx
ret
[SECTION .data]
@ -319,3 +365,22 @@ gdt_48:
idt16_descr:
dw 1024 ; idt enthaelt max. 1024 Eintraege
dd 0 ; Adresse 0
;
; Stack-Zeiger fuer Bluescreen
; (genauerer Stack-Aufbau siehe Bluescreen.cc)
;
; |-------------|
; |  EFLAGS |
; |-------------|
; | CS |
; |-------------|
; | EIP |
; |-------------|
; | [ErrorCode] |
; |-------------|
; | alle Regs. |
; | (PUSHAD) |
; |-------------| <-- int_esp
int_esp:
db 0,0,0,0