Category : Files from Magazines
Archive   : DDJ0989.ZIP
Filename : GREEN.LST

 
Output of file : GREEN.LST contained in archive : DDJ0989.ZIP
_80386 PROTECTED MODE AND MULTITASKING_
by Tom Green


[LISTINÇ ONE]

/************************************************************************/
/* 386.H - structures etc. for the 80386 */
/* By Tom Green */
/************************************************************************/

/* all of these structures are processor dependant, so */
/* you must set code generation for byte alignment */


/* generic descriptor - data, code, system, TSS */

typedef struct descriptor{
unsigned int limit_lo;
unsigned int base_lo;
unsigned char base_mid;
unsigned char type_dpl;
unsigned char limit_hi;
unsigned char base_hi;
}descriptor;

/* call, task, interrupt, trap gate */

typedef struct gate{
unsigned int offset_lo;
unsigned int selector;
unsigned char count;
unsigned char type_dpl;
unsigned int offset_hi;
}gate;

/* this is the layout for a task state segment (TSS) */
/* the fill fields of structures are not used by the 80386 */
/* but must be there */

typedef struct tss{
unsigned int back_link; /* selector for last task */
unsigned int fill1;
unsigned long esp0; /* stack pointer privilege level 0 */
unsigned int ss0; /* stack segment privilege level 0 */
unsigned int fill2;
unsigned long esp1; /* stack pointer privilege level 1 */
unsigned int ss1; /* stack segment privilege level 1 */
unsigned int fill3;
unsigned long esp2; /* stack pointer privilege level 2 */
unsigned int ss2; /* stack segment privilege level 2 */
unsigned int fill4;
unsigned long cr3; /* control register 3, page table */
unsigned long eip; /* instruction pointer */
unsigned long eflags;
unsigned long eax;
unsigned long ecx;
unsigned long edx;
unsigned long ebx;
Š unsigned long esp;
unsigned long ebp;
unsigned long esi;
unsigned long edi;
unsigned int es;
unsigned int fill5;
unsigned int cs;
unsigned int fill6;
unsigned int ss;
unsigned int fill7;
unsigned int ds;
unsigned int fill8;
unsigned int fs;
unsigned int fill9;
unsigned int gs;
unsigned int filla;
unsigned int ldt;
unsigned int fillb;
unsigned int tbit; /* exception on task switch bit */
unsigned int iomap;
}tss;

#define TSS_SIZE (sizeof(tss))
#define DESCRIPTOR_SIZE (sizeof(descriptor))
#define GATE_SIZE (sizeof(gate))
#define DPL(x) (x<<5)
#define TYPE_CODE_DESCR 0x18
#define TYPE_DATA_DESCR 0x10
#define TYPE_TSS_DESCR 0x09
#define TYPE_CALL_GATE 0x0c
#define TYPE_TASK_GATE 0x05
#define TYPE_INTERRUPT_GATE 0x0e
#define TYPE_TRAP_GATE 0x0f
#define SEG_WRITABLE 0x02
#define SEG_READABLE 0x02
#define SEG_EXPAND_DOWN 0x04
#define SEG_CONFORMING 0x04
#define SEG_ACCESSED 0x01
#define SEG_TASK_BUSY_BIT 0x02
#define SEG_PRESENT_BIT 0x80
#define SEG_GRANULARITY_BIT 0x80
#define SEG_DEFAULT_BIT 0x40
#define SELECTOR_MASK 0xfff8

[LISTING TWO]

/************************************************************************/
/* TASK.C - this code creates and sets up the Global Descriptor */
/* Table and Task State Segments. the code switches to protected */
/* mode, runs tasks, and returns to real mode. */
/* Compile with Turbo C 2.0 */
/* By Tom Green */
/************************************************************************/

#include
#include
#include
#include
#include "386.h"

/* selectors for entries in our GDT */
#define CODE_SELECTOR 0x08
#define DATA_SELECTOR 0x10
#define TASK_1_SELECTOR 0x18
#define TASK_2_SELECTOR 0x20
#define MAIN_TASK_SELECTOR 0x28
#define VID_MEM_SELECTOR 0x30

/* physical address of video ram, mono and color */
#define COLOR_VID_MEM 0xb8000L
#define MONO_VID_MEM 0xb0000L

/* video modes returned by BIOS call */
#define MONO_MODE 0x07
#define BW_80_MODE 0x02
#define COLOR_80_MODE 0x03

/* pointer to a function */
typedef void (func_ptr)(void);

/* extern stuff in mode.asm */
void protected_mode(unsigned long gdt_ptr,unsigned int cseg,unsigned int dseg);
unsigned int load_task_register(unsigned int tss_selector);
void real_mode(unsigned int dseg);
void jump_to_task(unsigned int tss_selector);


/* prototypes for local functions */
void task1(void);
void task2(void);
void init_tss(tss *t,unsigned int cs,unsigned int ds,unsigned char *sp,
func_ptr ip);
void init_gdt_descriptor(descriptor *descr,unsigned long base,unsigned long
limit,unsigned char type);
void print(unsigned int x,unsigned int y,char *s);
void vid_mem_putchar(unsigned int x,unsigned int y,char c);

/* this array of descriptors will be our Global Descriptor Table */
descriptor gdt[10];

/* these are the TSS's for our tasks */
Štss main_tss;
tss task_1_tss;
tss task_2_tss;

/* seperate stacks for each task */
unsigned char task_1_stack[1024];
unsigned char task_2_stack[1024];


/* global y location for protected mode screen writes */
/* using descriptor for video ram */
unsigned int y=0;

void main(void)
{
unsigned long base;
unsigned char type;
union REGS r;

/* setup code and data descriptors in GDT */

/* code GDT entry 1 */

/* turn code segment into 20 (and 32) bit physical base address */
base=((unsigned long)_CS)<<4;
/* set descriptor type for a readable code segment */
type=TYPE_CODE_DESCR | SEG_PRESENT_BIT | SEG_READABLE;
init_gdt_descriptor(&gdt[1],base,0xffffL,type);

/* data GDT entry 2 */

/* turn data segment into 20 (and 32) bit physical base address */
base=((unsigned long)_DS)<<4;
/* set descriptor type for a writeable data segment */
type=TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE;
init_gdt_descriptor(&gdt[2],base,0xffffL,type);

/* set up TSS's for tasks here */

/* set descriptor type for a TSS */
type=TYPE_TSS_DESCR | SEG_PRESENT_BIT;

/* put a descriptor for each TSS in the GDT */

/* TSS GDT entry 3, TSS for task1 */
/* turn segment:offset of task1 TSS into physical base address */
base=(((unsigned long)_DS)<<4)+(unsigned int)&task_1_tss;
init_gdt_descriptor(&gdt[3],base,(unsigned long)TSS_SIZE-1,type);

/* TSS GDT entry 4, TSS for task2 */
/* turn segment:offset of task2 TSS into physical base address */
base=(((unsigned long)_DS)<<4)+(unsigned int)&task_2_tss;
init_gdt_descriptor(&gdt[4],base,(unsigned long)TSS_SIZE-1,type);

/* TSS GDT entry 5, TSS for main starting task */
Š /* turn segment:offset of main TSS into physical base address */
base=(((unsigned long)_DS)<<4)+(unsigned int)&main_tss;
init_gdt_descriptor(&gdt[5],base,(unsigned long)TSS_SIZE-1,type);

/* init the TSS with starting values for each task */

/* task 1 */
init_tss(&task_1_tss,CODE_SELECTOR,DATA_SELECTOR,task_1_stack+
sizeof(task_1_stack),task1);

/* task 2 */
init_tss(&task_2_tss,CODE_SELECTOR,DATA_SELECTOR,task_2_stack+
sizeof(task_2_stack),task2);

/* video ram descriptor GDT entry 6 */

/* set descriptor for a writeable data segment */
type=TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE;
r.h.ah=15; /* get video mode BIOS */
int86(0x10,&r,&r);
/* check if mono mode */
if(r.h.al==MONO_MODE)
init_gdt_descriptor(&gdt[6],MONO_VID_MEM,3999,type);
/* check if color mode */
else if(r.h.al==BW_80_MODE || r.h.al==COLOR_80_MODE)
init_gdt_descriptor(&gdt[6],COLOR_VID_MEM,3999,type);
else{
printf("\nThis video mode is not supported.");
exit(1);
}

/* we are now ready to enter protected mode */

clrscr();
cprintf("\nPress return to enter protected mode.");
getchar();

/* turn segment:offset of GDT into 20 bit physical address */
base=(((unsigned long)_DS)<<4)+(unsigned int)&gdt;

/* this puts us in protected mode */
protected_mode(base,CODE_SELECTOR,DATA_SELECTOR);

/* this loads the task register for the first task */
load_task_register(MAIN_TASK_SELECTOR);

y=3; /* this is line we will start printing on in protected mode */
/* using our descriptor to write to video ram */

print(0,y++,"Entered protected mode in main task");

/* this jumps to first task (which will jump back here eventually) */
jump_to_task(TASK_1_SELECTOR);

print(0,y++,"Returned to main task, leaving protected mode");
Š
/* return us to real mode */
real_mode(DATA_SELECTOR);

gotoxy(1,22);
cprintf("Returned to real mode. Press return to exit to DOS");
getchar();
clrscr();
}

/* code for task 1 */

void task1(void)
{
while(1){
print(0,y++,"Hello from task1");
jump_to_task(TASK_2_SELECTOR);
/* return to original task (in main()) after several task switches */
if(y>18)
jump_to_task(MAIN_TASK_SELECTOR);
}
}

/* code for task 2 */

void task2(void)
{
while(1){
print(0,y++,"Hello from task2");
jump_to_task(TASK_1_SELECTOR);
}
}

/* this initializes a TSS */
/* inits segment registers, eip, and stack stuff to starting values */

void init_tss(tss *t,unsigned int cs,unsigned int ds,unsigned char *sp,
func_ptr ip)
{
t->cs=cs; /* code selector */
t->ds=ds; /* set these to the data selector */
t->es=ds;
t->ss=ds;
t->fs=ds;
t->gs=ds;
t->eip=(unsigned int)ip; /* address of first instruction to execute */
t->esp=(unsigned int)sp; /* offset of stack in data */
t->ebp=(unsigned int)sp;
}

/* this initializes a descriptor in the Global Decsriptor Table */
/* sets up the base, limit, type, and granularity */

void init_gdt_descriptor(descriptor *descr,unsigned long base,unsigned long
limit,unsigned char type)
Š{
descr->base_lo=(unsigned int)base;
descr->base_mid=(unsigned char)(base >> 16);
descr->type_dpl=type;
/* if limit > 0xfffffL then we have to set granularity bit and shift */
if(limit > 0xfffffL){
limit = limit >> 12;
descr->limit_hi=((unsigned char)(limit >> 16) & 0xff) |
SEG_GRANULARITY_BIT;
}
else
descr->limit_hi=((unsigned char)(limit >> 16) & 0xff);
descr->limit_lo=(unsigned int)limit;
descr->base_hi=(unsigned char)(base >> 24);
}

/* this routine prints a string using vid_mem_putchar */

void print(unsigned int x,unsigned int y,char *s)
{
while(*s)
vid_mem_putchar(x++,y,*s++);

}

/* this routine writes a character directly to video ram */
/* uses the selector for the descriptor we set up in main */
/* for video ram */

void vid_mem_putchar(unsigned int x,unsigned int y,char c)
{
register unsigned int offset;
char far *vid_ptr;

offset=(y*160) + (x*2);
/* make our far pointer use our special video ram descriptor */
/* yes, we can even use far pointers with selectors */
vid_ptr=MK_FP(VID_MEM_SELECTOR,offset);
*vid_ptr++=c; /* write character */
*vid_ptr=0x07; /* write attribute byte */
}


[LISTING THREE]

;*****************************************************************
; MODE.ASM
; Routines for switching to protected and real mode. Also includes
; routines for loading task register and jumping to a task.
; Assemble with Turbo TASM 1.0
; By Tom Green
;*****************************************************************

.MODEL SMALL

.386P

.DATA

;this is where we stuff address of GDT that is passed
gdtptr LABEL PWORD
dw 50h ;size in bytes of GDT, enough for 10 entries
dd ? ;this is where we will put physical address of GDT

;this is where we will store the address of a task (the selector) that
;we will jump to in jump_to_task
new_task LABEL DWORD
dw 00h
new_select LABEL WORD
dw 00h

;this is where we store address to jump to when we enter protected mode
;in protected_mode
;offset of code where we will jump
p_mode LABEL DWORD
dw OFFSET protect
;put selector of protected mode code segment here
p_mode_select LABEL WORD
dw 0

.CODE

PUBLIC _real_mode,_protected_mode,_jump_to_task
PUBLIC _load_task_register

;*****************************************************************
; void protected_mode(unsigned long gdt_ptr,unsigned int cseg,
; unsigned int dseg) - puts 386 in protected mode and loads segment
; registers with code and data selectors passed (cs and ds
; parameters). pass this routine a 32 bit physical address of the
; Global Descriptor Table (gdt_ptr parameter). Turns interrupts
; off while we run in protected mode.
;*****************************************************************
_protected_mode PROC NEAR
push bp
mov bp,sp
mov ax,[bp+4] ;get low word of address of GDT
mov dx,[bp+6] ;get high word of address of GDT
mov WORD PTR gdtptr+4,dx ;store high word of address of GDT
mov WORD PTR gdtptr+2,ax ;store low word of address of GDT
Š mov ax,[bp+8] ;get selector for code descriptor
mov dx,[bp+10] ;get selector for data descriptor
mov p_mode_select,ax ;put code selector in our jmp pointer
mov eax,0 ;prepare to zero out eflags
push eax
popfd ;zero out eflags
lgdt PWORD PTR gdtptr ;load gdt register with limit and ptr
mov eax,cr0
or eax,1
mov cr0,eax ;turn protected mode on
jmp DWORD PTR p_mode ;this will jump to protect through ptr
;(cs will be loaded with code selector)
protect:
;we are now running in protected mode, and we will load segment registers
;with selectors that look like our code is still in real mode
mov ss,dx ;load segment registers with data selector
mov ds,dx
mov es,dx
mov fs,dx
mov gs,dx
mov ax,0
lldt ax ;make sure ldt register has 0
pop bp
ret
_protected_mode ENDP

;*****************************************************************
; void load_task_register(unsigned int tss_selector) -
; loads task register with TSS selector
;*****************************************************************
_load_task_register PROC NEAR
push bp
mov bp,sp
ltr [bp+4] ;load task register with selector for current task
pop bp
ret
_load_task_register ENDP

;*****************************************************************
; void real_mode(unsigned int dseg) -
; returns 386 to real mode. pass this routine the selector for
; a 64k data segment so we can return to real mode. this
; routine assumes we are executing from a 64k data segment.
; (80386 segment registers must have selector of segment with
; 64k limit to return to real mode)
;*****************************************************************
_real_mode PROC NEAR
push bp
mov bp,sp
mov ax,[bp+4] ;get selector for data segment
mov ds,ax ;now make sure all segment registers
mov es,ax ;contain selector to 64k segment
mov fs,ax ;must have this to return to real mode
mov gs,ax
mov ss,ax
Š mov eax,cr0
and eax,07ffffffeh
mov cr0,eax ;protected mode off
jmp FAR PTR flush ;flush queue and set cs for real mode
;now cs will be loaded with correct
;segment for real mode
flush:
mov ax,DGROUP ;restore data seg registers for real mode
mov ds,ax
mov ss,ax
mov es,ax
sti ;interrupts back on for real mode
pop bp
ret
_real_mode ENDP

;*****************************************************************
; void jump_to_task(unsigned int tss_selector) -
; jumps to 386 TSS task. pass this routine the selector of the
; TSS of the task you want to jump to.
;*****************************************************************
_jump_to_task PROC NEAR
push bp
mov bp,sp
mov ax,[bp+4] ;get selector of new task
mov new_select,ax ;store it in pointer
jmp DWORD PTR new_task ;jump to task through selector:offset ptr
pop bp
ret
_jump_to_task ENDP

END




  3 Responses to “Category : Files from Magazines
Archive   : DDJ0989.ZIP
Filename : GREEN.LST

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/