/*----------------------------------------------------------------------------------------------------- SISTEMA OPERACIONAL - carregar execut vel ---------------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include "so.h" /*** declara‡”es de vari veis globais ***/ dt idt, gdt; // interrupt table e global descriptor table logAddr ativo; // endere‡o logico do programa a ser carregado // e executado segment *base_ldt_atual; // endere‡o do inicio da LDT atual /*** declara‡”es de referˆncias externas e internas ***/ extern void cadastrar(int matricula); extern void inicializar(int modo); // v¡deo gr fico //*** Recuperamos alguns valores de registradores de sistema //*** da CPU para ficar em vari veis globais, facilitando o acesso a eles. void get_system_regs() { asm sidt [idt] // armazena base da IDT asm sgdt [gdt] // armazena base da GDT } /*** rotinas para leitura de descritores ***/ // substituir: segment *seg_do_sel(word sel) { // As v ri veis globais gdt e base_ldt_atual precisam // estar setados corretamente. selector s = eq(selector)sel; if(s.ldt) return( base_ldt_atual + s.index ); else return( gdt.base.seg + s.index ); } void *base_do_seg(segment *segp) { return( (void *)(segp->a.base&0xFF000000 | segp->b.base&0x00FFFFFF ) ); } void *base_do_sel(word sel) { return( base_do_seg(seg_do_sel(sel)) ); } dword size_do_sel(word sel) { return( ( seg_do_sel(sel)->a.limit&0xFFFF ) + 1 ); } tss *base_do_tss(word sel) { selector s = eq(selector)sel; access acc = eq(access)gdt.base.seg[s.index].c.access; if(!(acc.s==SPECIAL && (acc.type==TSS_AVAILABLE || acc.type==TSS_BUSY ))) { fprintf(stderr,"Error: tssBase: selector %X is not a TSS\n",sel); exit(2); } return(base_do_sel(sel)); } /*** rotinas para preenchimento de descritores ***/ // preenchimento de descritor de interrupt gate, call gate ou task gate void faz_gate(gate *desc, logAddr sr, byte access) { desc->b.offset = desc->a.offset = sr.offset; //call Address; desc->b.selector = sr.selector; //call Selector; desc->a.access = access; desc->a.params = 0; } // preenchimento de um descritor de segmento para size<2^16 void faz_segment(segment *desc, dword size, byte acesso) { static byte *linear = USER_SEG_MEM_INI; access acc = eq(access)acesso; desc->a.limit = size-1; desc->b.base = desc->a.base = linear; desc->c.access = acesso; desc->c.bitsize = 0x40; // trata-se de uma LDT ? if(acc.s==SPECIAL && acc.type==LDT) base_ldt_atual = linear; linear += size; } // preenchimento de um novo descritor de segmento na GDT word faz_gdt_segment(dword size, byte acesso) { static word livre = USER_SEG_INDEX_INI; // index livre na GDT selector s; access acc = eq(access)acesso; faz_segment(&gdt.base.seg[livre], size, acesso); // constroi seletor para o descritor criado s.index = livre; s.ldt = 0; s.pl = acc.dpl; // RPL = DPL livre++; // passa para a proxima posicao livre na GDT return(eq(word)s); } /* rotina especial para criar o segmento de v¡deo */ void descVideo() { dword *desc = (dword *)(gdt.base.seg + VIDEO_INDEX); desc[1] = 0xE04BF200; // base = 0xE0000000, size=1024*768-1 desc[0] = 0x0000FFFF; // tipo = 0xF2 (s=NORNAL type=DATA_READ_WRITE pl=USERPL) } // preenchimento de novo PCB, incluindo LDT word new_task(userSize *user) { selector sel; access acc; word pcbSel; // seletor da nova TSS na GDT tss *pcb; // PCB do novo processo a ser instanciado segment *ldt; // LDT do novo processo acc.p = 1; // descritor presente - vale para todos // ****** primeiro os descritores especiais com privil‚gio sistema acc.dpl = SYSTEMPL; acc.s = SPECIAL; // Task State Segment acc.type = TSS_AVAILABLE; pcbSel = faz_gdt_segment(sizeof(tss), eq(byte)acc); pcb = base_do_tss(pcbSel); pcb->status = novo; pcb->cr3 = _CR3; // a mesma pagina‡„o para todos pcb->eflags = 0x202; // settar interrupt flag, permitindo interrup‡”es pcb->iopb = sizeof(tss); // prote‡„o total de I/O pcb->eip = 0; // 'main' do usu rio ‚ no in¡cio // Local Desciptor Table acc.type = LDT; pcb->ldtr = faz_gdt_segment(6*sizeof(segment), eq(byte)acc); ldt = base_do_sel(pcb->ldtr); // Pilha para system calls e interrup‡”es do processo acc.s = NORMAL; acc.type = DATA_READ_WRITE; pcb->ss0 = faz_gdt_segment(USER_STACK0_SIZE, eq(byte)acc); pcb->esp0 = USER_STACK0_SIZE; // *** a partir d'aqui segmentos de privilegio usuario na LDT sel.ldt = 1; sel.pl = USERPL; acc.dpl = USERPL; // segmento de dados constantes acc.type = DATA_READ_ONLY; faz_segment(ldt + (sel.index=1), user->datasize, eq(byte)acc); pcb->es = eq(word)sel; // Segmento de c¢digo acc.type = CODE_EXECUTE_ONLY; faz_segment(ldt + (sel.index=2), user->codesize, eq(byte)acc); pcb->cs = eq(word)sel; // Segmento de vari veis acc.type = DATA_READ_WRITE; faz_segment(ldt + (sel.index=3), user->varsize, eq(byte)acc); pcb->ds = eq(word)sel; // Pilha do processo acc.type = DATA_READ_WRITE; faz_segment(ldt + (sel.index=4), user->stacksize, eq(byte)acc); pcb->ss = eq(word)sel; pcb->esp = user->stacksize; return(pcbSel); } /* carregar um arquivo execut vel */ word carregar(char exechar) { static char exename[] = "c:us ."; // nome do arquivo (com prefixo) static userSize header; // cabe‡alho do execut vel static unsigned int exehandle, result; word pcbSel; // seletor do novo PCB tss *pcb; // apontador para o novo PCB word save_ES = _ES; // Esta rotina cont‚m chamadas … libc _ES = _DS; // as quais devem ser usadas com ES apropriado. exename[strlen(exename)-2] = exechar; // colocar exechar no final do nome if (_dos_open(exename, O_RDONLY, &exehandle) ) { puts("Execut vel "); puts(exename); puts(" ausente.\n"); exit(1); } // Cabe‡alho if (_dos_read(exehandle, &header, sizeof(header), &result) || result!=sizeof(header)) { puts("N„o consigo ler o cabe‡alho do execut vel.\n"); exit(1); } pcbSel = new_task(&header); pcb = base_do_sel(pcbSel); // Segmento de dados constantes if (_dos_read(exehandle, base_do_sel(pcb->es), header.datasize, &result) || result!=header.datasize) { puts("N„o consigo ler os dados do execut vel.\n"); exit(1); } // Segmento de c¢digo if (_dos_read(exehandle, base_do_sel(pcb->cs), header.codesize, &result) || result!=header.codesize) { puts("N„o consigo ler os dados do execut vel.\n"); exit(1); } debug(base_do_sel(pcb->cs), exename); // RPC para o depurador _dos_close(exehandle); _ES = save_ES; // Coloque valor original em ES. return(pcbSel); } //*** rotinas de atendimento a system calls e interrup‡”es // a tecla "espa‡o" p ra a tarefa no depurador _interrupt void tecla (dword edi, dword esi, dword ebp, dword esp, dword ebx, dword edx, dword ecx, dword eax, dword gs, dword fs, dword es, dword eip, dword cs, dword eflags) { inportb(0x64); // read keyboard status if( inportb(0x60) == 0x39 ) // tecla == "espa‡o" ? eflags |= 0x100; // se sim, settar trap flag EOI1; } // cria descritores de call gate, interrupt gate, etc. void faz_system_gates () { access acc; // campo de acesso para os descritores logAddr sr; // endere‡o l¢gico de uma rotina de atendimento acc.p = 1; acc.dpl = USERPL; acc.s = SPECIAL; asm cli // desabilita interrupcoes para poder mexer na IDT // Interrupt Gate para o teclado (somente para depura‡„o) acc.type=INTERRUPT_GATE; sr.offset = &tecla; sr.selector = _CS; faz_gate(idt.base.gate+KEYBOARD, sr, eq(byte)acc); } int main() { selector sel; char c; cadastrar(29912345); //    COLOQUE AQUI SUA MATRICULA SEM 'g'    //******* agora vamos dar boot no NOSSO get_system_regs(); faz_system_gates(); // Segmento de v¡deo descVideo(); inicializar(5); // cria o primeiro processo de usu rio isso vai ser o valor de `ativo' ativo.selector = carregar('a'); asm jmp [ativo] fprintf(stderr,"NOSSO shut down.\n"); return(0); }