Lecture 5: April 12, 2012.

By: Corey Quon, Maria Tio, Rhys Yu, & Naseem Makiya

Ways of Getting Hard Modularity:

1) Client/Service Organization

Suppose we want to impose hard modularity on a factorial program:

Client:
send({"1", 5}, factserver);
receive(factserver, response);
if (response.code == "ok")
print(response.val);
else
print("error", response.code);

Server:
for (;;)
{
receive(ANYBODY, request);
if (request.opcode == "!")
{
n = fact(request.val);
response = {"ok", n};
}
else
{
response = {"ng", 0};
}
send(request.send, response);
}

Advantages (+) and Disadvantages (-):

2) Virtualization

Client:
a = fact(b);
int fact(int n)
{
asm("fact, %d, %eax");
}

To get this virtual machine, write a C program to emulate x86:

C program:
int ecp;
int eax;
char mem[1024 * 1024 * 1024];
for (;;)
{
char insn = mem[eip++];
switch (insn)
{
case 221: eax = fact(eax); //<--code added
}
}

Advantages of virtualization:
Suppose the client does bad things:

Disadvantages of virtualization:

We (server maintainers) need a virtualizable processor

We need protected transfer control

By convention on x86

Processor has a 'privileged bit'

When the hardware traps, it enables this bit.
diagram1

To do protected transfer control:
On a trap, the x86 hardware does the following...

  1. pushes 6 words on stack to do protected transfer control
  2. goes on the Interrupt Service Vector and checks which code to execute using the isvn[n]
  3. syscall convention on Linux,

Home kernel decides how virtual kernel should proceed

We want to support more than one application "simultaneously" even on a one-core CPU.
To do this, the kernel records each app's state
diagram2

Syscalls for manipulating processes!