Laboratório de Organização e Arquitetura de Computadores Segmentação (Conceitos Básicos) PROFESSORES: Elmar Uwe Kurt Melcher Joseana Macêdo Fechine /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ #define VIDEOSEL 0x1000 /*** struct and type declarations ***/ typedef unsigned char byte; typedef unsigned short word; typedef unsigned int dword; /* endereco segmentado (endereco logico) */ struct segaddr { void *addr; word selector; }; typedef struct segaddr *segaddr_ptr; // tornar um seletor um indice da tabela de descritores de segmentos #define segidx(selector) (selector>>3) /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ /* descritor de segmento. Cada sub-estrutura serve para preencher uma parte dos campos do descritor. Devem ser usados na sequencia a, b, c.*/ union segment { /* Nenhum dos itens na, nb deve ser usado. */ struct { // COLOCO BASE E LIMITE OS DEMAIS FICAM ERRADO dword limit; dword base; } a; struct { word na; dword base; } b; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ struct { //CONSERTA O TYPE E O BIT SIZE dword na; byte nb; byte type; byte bitsize; } c; }; typedef union segment *segment_ptr; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ /* IDTR e GDTR */ struct dtr { word length; union { gate_ptr g; segment_ptr s; } base; }; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ // Tem quase tudo que tem dentro do do processador //FUNCAO: salvar o contexto do processador struct tss { /* itens na ate nk sao reservados */ word link, na; dword esp0; word ss0, nb; dword esp1; word ss1, nc; dword esp2; word ss2, nd; dword cr3; //da paginacao dword eip; //PC dword eflags; //PSW dword eax, ecx, edx, ebx; dword esp, ebp; dword esi, edi; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ word es, ne; word cs, nf; word ss, ng; word ds, nh; word fs, ni; word gs, nj; word ldtr, nk; word t; word iopb; }; typedef struct tss *tss_ptr; //Descritores /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ /*** declaracoes de variaveis globais ***/ /* interrupt table e global descriptor table */ struct dtr idtr, gdtr; /* rotina especial para prencher o segmento de video */ void descVideo() { dword *desc = (dword *)(gdtr.base.s + segidx(VIDEOSEL)); desc[1] = 0xE04BF200; // base = 0xE0000000, limit=BFFFFh=1024*768-1<>1M desc[0] = 0x0000FFFF; // tipo = 0xF2, dpl=3, read/write } /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ /* carregar um arquivo executavel */ void carregar(char *exename) { FILE *exefile; // cabecalho do execut vel static struct { dword datasize, codesize, varsize, stacksize; } header; if((exefile=fopen(exename,"rb"))==NULL) { fprintf(stderr,"Executavel %s ausente.\n", exename); exit(1); } if(fread(&header, sizeof(header), 1, exefile)!=1) { fprintf(stderr,"Nao consigo ler o cabecalho do executavel.\n"); exit(1); } /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ //Preenchendo o descritor(seletor) de dados constantes gdtr.base.s[segidx(0x1048)].a.limit = header.datasize-1; //o limite esta no cabecalho -1 pois comeca em 0 gdtr.base.s[segidx(0x1048)].a.base = 0x01989866; //a base do segmento a, um endereco gostoso gdtr.base.s[segidx(0x1048)].b.base = 0x01989866; //a base do segmento a, um endereco gostoso gdtr.base.s[segidx(0x1048)].c.type = 0xF0; // dpl=usuario, permite so leitura gdtr.base.s[segidx(0x1048)].c.bitsize = 0x40; // do descritor 32 bits /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ //Preenchendo o descritor(seletor) de codigo gdtr.base.s[segidx(0x1050)].a.limit = header.codesize-1; //o codesize est no cabecalho, -1 pois comeca em 0 gdtr.base.s[segidx(0x1050)].a.base = 0x01AA9866; //a base do segmento a, o max ‚ FFFFFFF... gdtr.base.s[segidx(0x1050)].b.base = 0x01AA9866; //a base do segmento a, o max ‚ FFFFFFF... gdtr.base.s[segidx(0x1050)].c.type = // 0x98; // dpl = S.O., permite execucao 0xF8; // dpl=usuario, permite execucao gdtr.base.s[segidx(0x1050)].c.bitsize = 0x40; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ //Preenchendo o descritor(seletor) de variaveis gdtr.base.s[segidx(0x1058)].a.limit = header.varsize-1; //o limite est no cabecalho, -1 pois comeca em 0 gdtr.base.s[segidx(0x1058)].a.base = 0x01BB9866; //a base do segmento a, o max ‚ FFFFFFF... gdtr.base.s[segidx(0x1058)].b.base = 0x01BB9866; //a base do segmento a, o max ‚ FFFFFFF... gdtr.base.s[segidx(0x1058)].c.type = 0xF2; // dpl=usuario, permite ler e escrever gdtr.base.s[segidx(0x1058)].c.bitsize = 0x40; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ //Preenchendo o descritor(seletor) de pilha gdtr.base.s[segidx(0x1060)].a.limit = header.stacksize-1; //o limite est no cabecalho, -1 pois comeca em 0 gdtr.base.s[segidx(0x1060)].a.base = 0x01CC9866; //a base do segmento a, o max ‚ FFFFFFF... gdtr.base.s[segidx(0x1060)].b.base = 0x01CC9866; //a base do segmento a, o max ‚ FFFFFFF... gdtr.base.s[segidx(0x1060)].c.type = 0xF2; // dpl=usuario, permite ler e escrever gdtr.base.s[segidx(0x1060)].c.bitsize = 0x40; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ //Colocando os dados depois de carregar o cabecalho if(fread(&0x01989866, header.datasize, 1, exefile)!=1) { // fread(end da base, quantidade de dados,= ) fprintf(stderr,"Nao consigo ler os dados.\n"); exit(1); } //Colocando o codigo depois de carregar o cabecalho if(fread(&0x01AA9866, header.codesize, 1, exefile)!=1) { fprintf(stderr,"Nao consigo ler o codigo.\n"); exit(1); } fclose(exefile); } /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ void criaTss() { static struct tss estado; //Descritor de Segmento para o TSS gdtr.base.s[segidx(0x1068)].a.limit = sizeof(estado); //o limite do segmento de pilha gdtr.base.s[segidx(0x1068)].a.base = &estado; // gdtr.base.s[segidx(0x1068)].b.base = &estado; // gdtr.base.s[segidx(0x1068)].c.type = 0x89; //tipo do segmento. no descriptor do segmento (p=1,dpl=00,s=0), onde o s tem que ser 8. gdtr.base.s[segidx(0x1068)].c.bitsize = 0x40; //0/0 do descrittor 32 bist? /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ // preenchimento da TSS estado.eflags = 0x202; // PSW estado.ldtr = 0x828; // eh assim mesmo estado.iopb = sizeof(struct tss); // todos os seletores com rpl=3=usuario estado.cs = 0x1050+3; //codigo estado.ds = 0x1048+3; //dados estado.es = 0x1058+3; //variaveis estado.gs = 0x1000+3; //ram de video estado.ss = 0x1060+3; //Pilha /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ // preenchimento da TSS asm mov eax,cr3; //recuperando o cr3 do SO estado.cr3 = _EAX ;//estrutura de paginacao, coloco igual ao do SO estado.eip = 0 ;//codigo do usuario comeca em zero estado.esp = (word)gdtr.base.s[segidx(0x1060)].a.limit + 1;//topo da pilha, no limite //para nao travar quando chegar uma interrupcao estado.esp0 = _ESP; asm mov ax,ss estado.ss0 = _EAX ; /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ _far void sair(){ asm mov ax,0x930 // garantir espaco total para todos os segmentos asm mov ds,ax asm mov es,ax asm mov fs,ax exit(0); } /* -------------------------------------------------------------------------------------------SOFTWARE BASICO - carregador -------------------------------------------------------------------------------------------*/ void criaCallGate() { static word so_cs; // seletor de codigo do S.O. // preenchendo o call gate // sair sera chamada pelo codigo do usuario gdtr.base.g[segidx(0x1070)].a.offset = &sair; gdtr.base.g[segidx(0x1070)].b.offset = &sair; asm mov ax,cs asm mov [so_cs],ax gdtr.base.g[segidx(0x1070)].b.selector = so_cs; gdtr.base.g[segidx(0x1070)].a.params = 0; gdtr.base.g[segidx(0x1070)].a.type = 0xEC; //no test.c (pode ser a 1a instrucao do main) temos que introduzir: asm call 0x1070:0 } int main() { cadastrar(20111011); /* Recupera alguns valores do S.O. para ficar em variaveis globais. */ asm sidt asm sgdt [idtr] // armazena inicio da IDT [gdtr] // armazena inicio da GDT /* Segmento de video */ descVideo(); initializar(5); carregar("test"); // carrega o processo de usuario criaTss(); criaCallGate(); // asm jmp 0x1050:0; // superjump: pula para outro segmento asm jmp 0x1068:0; // hiperjump: pula para outro contexto (TSS) return 0; // } /* -------------------------------------------------------------------------------------------APLICATIVO – Test.c -------------------------------------------------------------------------------------------*/ // system call #define systemcall asm call 0x1070:0 dword dummy; // definição de uma variavel apenas para preecher o segmento correspondente (32 bits) // prototipos void desenhar_fractal(); void main() { // A primeira rotina do programa deve ser o main desenhar_fractal(); systemcall; } // chamada ao S.O. Segmentação - Passos 1. Observar a Tabela da GDT nos endereços 928, 930, .... E 810 - Busy). (TR 2. Observar na Tabela de memória os segmentos de dados e de código (Alt +D, Alt +C). 3. Executar descVideo() e observar na tabela da GDT a posição 1000. 4. Executar carregar(“test”) e observar o conteúdo da GDT em 1048, 1050, 1058, 1060. 5. Executar CriaTSS() e observar o conteúdo da GDT em 1068 (Available, Salva o contexto do aplicativo). 6. Executar CriaCallGate() e observar o conteúdo da GDT em 1070. 7. Executar JMP 0x1068:00 e observar a memória (tamanho do segmento-Aplicativo), 1068 da GDT (Busy) e 810 (Available) e o valor do EIP (0). 8. Executar no aplicativo o systemcall (call 0x1070:00).