Esse documento representa parte dos meus estudos acerca do Livro - Operational Systems Three Easy Pieces, de dominio publico.


Segmentacao, apesar de ser quase sempre necessaria no sistema que estamos construindo, causa alguns problemas que sao dificeis de ser mantidos. Como criamos espacos segmentados, nao contiguos como em outros tipos de alocacao, podemos gerar uma fragmentacao, com blocos de tamanhos diferentes.

Para garantir o tamanho dos espacos na memoria, podemos usar uma tecnica chamada paginacao, que ja foi vista nas aulas sobre arvores B.

No geral, uma pagina eh uma estrutura de tamanho definido e contigua na memoria, que consegue (ou nao) ser a estrutura que carrega dados da memoria secundaria. Neste caso, estamos utilizando paginacao unica e exclusivamente com memoria principal, ou seja, temos que achar uma maneira de virtualizar a memoria com paginas.

Paginacao

Cada parte da memoria fisica, portanto, pode ser vista como um vetor com slots tamanho definido chamados de page frames.

Podemos criar, portanto, uma separacao da memoria fisica em paginas, de tamanho fisica (e.g. 128b), dessa forma, caso o alocador precise de, por exemplo 256b de memoria para alocar, ele pode simplesmente retorna 2 paginas livres.

Podemos, tambem, manter registro das paginas livres em uma estrutura similar a do capitulo anterior, assim garantindo uma grande facilidade no acesso a memoria.

Para melhorar ainda mais o desempenho, podemos usar uma page table mantida por cada processo. Essa tabela eh responsavel por armazenar as traducoes de endereco para cada pagina virtual no address space. EX: (Virtual Page 0 -> Physical Frame 3) (VP 1 -> PF 7) e por ai vai.

Traducao do endereco

Para fazermos a traducao, precisamos saber o tamanho de casa pagina. Se as paginas tem tamanho 16-bytes num addres space de tamanho 64-byte, entao, podemos representar o endereco de toda pagina com 6 bits, pois $2^{6} = 64$. Nesse sentido, pegamos os 2 bits mais significativos e os chamamos de VPN (Virtual Page Number), o resto, nos mostra o offset do comeco da pagina ate o byte que estamos interessados.

Essa conta toda nos dara um endereco virtual, por exemplo:

se tivermos os bits [ 010101 ], pegamos os 2 mais significativos (01 = 2) como VPN e o resto como offset (0101 = 5).

Agora, com o VPN em maos, podemos jogar o valor (01 = 2) na page table e ela nos dara o endereco real (PFN) Page Frame Number.

Num exemplo: 010101 -> 111(PFN)0101(offset) -> 117 em decimal, ou seja, na pagina 6 (112/16 = 6) + 5 bytes de offset.

Page table

Podemos salvar a page table apenas como uma simples array. O SO indexa o vetor pelos VPN (Virtual Page Number) e olha para a PTE (Page Table Entry) para retornar o Endereco fisico.

Cada PTE (Page Table Entry) tem um bit de validacao, por exemplo, que indica se a traducao gerada eh valida ou nao, ou seja, toda memoria livre sera marcada com um bit 0 de invalidacao, garantindo que nenhuma memoria nao alocada possa ser acessada.

Podemos tambem usar bits de protecao, que indicam se uma pagina pode ser lida, escrita ou executada. (r-w-x)

Outros exemplos:

  • Present Bit: indica se a pagina esta na memoria principal ou secundaria (swapping)
  • Dirty Bit: indica se a pagina foi editada desde que carregada na memoria
  • Reference Bit: indica se a pagina foi acessada e ajuda a determinar quais paginas sao mais populares e deveriam ser deixadas na memoria.
// acessando memoria com paging
// extrair o Virtual Page number do endereco virtual
VPN = (VirtualAddress & VPN_MASK ) >> SHIFT;

// formar o endereco da page-table entry (PTE)
PTEAddr = PTBR + (VPN * sizeof(PTE));

PTE = AccessMemory(PTEAddr);

// verificar se o processo pode acessar a pagina
if (PTE.Valid == False) {
    // SEG_FAULT
}
else if (CanAccess(PTE.ProtectBits) == False) {
    // PROTECTION_FAULT
}
else {
    // acesso liberado
    offset = VirtualAddress & OFFSET_MASK;
    PhysAddr = (PTE.PFN << PFN_SHIFT) | offset;
    Register = AccessMemory(PhysAddr)
}

Bibliografia

https://pages.cs.wisc.edu/~remzi/OSTEP/vm-paging.pdf