Operating Systems Homework
home/bshapir/cs314/project4/option1/lab4_1/lab4.ppt
Lab 4: Memory Management
Lab 4
- Part 1: Dynamic one-level paging
- Part 2: Dynamic two-level paging
- Part 3: Shared memory
lab4-1: Dynamic one-level page
- DLXOS so far
- Static one-level page table
- Single 64KB page
- memory.h:
- #define MEMORY_L1_PAGE_SIZE_BITS 16
- #define L1_MAX_ENTRIES 0x01
- process.c: ProcessFork()
- pcb->npages = 1;
lab4-1: Dynamic one-level page
- Page size: 8kb
- 256 total pages, 2mb total space
- Max 512kb virtual space per process
- Max 16 physical pages per process
- Track using PCB->npages
- Allocate 3 pages of test & data, 1 page of user stack when creating a process.
Lab4-1: The Translation
Page 0
Page 1
Page 2
…
Page N-2
Page N-1
Frame
Number
Valid
Flag
page table
Virtual Address
offset
Physical Address
offset
(512KB 19bit)
Frame Number
(2MB 21bit)
Page Number
Lab4-1: To do
- memory.h
- MEMORY_L1_PAGE_SIZE_BITS
- MEMORY_L2_PAGE_SIZE_BITS
- L1_MAX_ENTRIES, …
- memory.c: MemoryTranslateUserToSystem()
- Translate virtual address to physical address using page table
- process.c: ProcessFork()
- Allocate initial pages (text, data & stack)
- User stack at the high end of virtual address
- process.c: ProcessFreeResources()
- Free pages when process exits.
Lab4-1: More to do
- process.c: PageFaultHandler()
- Handle TRAP_PAGEFAULT trap (traps.c).
- Allocate new page and fix page table
- process.c: ProcessKill()
- Called when process exits, handling TRAP_ACCESS (traps.c)
- Free resource (queue, memory, …)
Utility functions
- MemoryAllocPage()
- Allocate a page of memory and return page number.
- MemorySetupPte()
- Given a page number, return the page table entry.
- MemoryFreePage()
- Given a page table entry, free the page.
Lab4-2: Dynamic two-level paging
- Virtual address space per process: 16MB
- How many bits is virtual address?
- Page size: 8kb
- How many pages one process has?
- One L1 page table entry corresponds to 512kb
- How many entries in L1, L2 page tables?
- Max 1MB physical space per process
- Allocate 3 pages of test & data, 1 page of user stack when creating a process.
Two Level Paging
L1
Virtual Memory
16MB
0
L2
To do
- memory.h
- MEMORY_L1_PAGE_SIZE_BITS
- MEMORY_L2_PAGE_SIZE_BITS
- L1_MAX_ENTRIES, L2_MAX_ENTRIES …
- process.c: ProcessFork()
- Allocate initial L2 page table and initial page (text, data & stack)
- User stack at the high end of virtual address
- process.c: ProcessFreeResources()
- Free pages when process exit.
- memory.c: MemoryTranslateUserToSystem()
- Translate virtual address to physical address
More to do
- process.c: PageFaultHandler()
- Handle TRAP_PAGEFAULT trap (traps.c).
- Allocate new page and fix L1, L2 page table
- process.c: ProcessKill()
- Called when process exits, handling TRAP_ACCESS (traps.c)
- Free resource (queue, memory, …)
home/bshapir/cs314/project4/option1/lab4_1/dlxsim.cc
home/bshapir/cs314/project4/option1/lab4_1/dlxsim.cc
//
// dlxsim.cc
//
// DLX simulator code. This is a barebones simulator, but it does
// include code to handle OS issues such as virtual memory translation.
// This allows it to be used as a simulator for operating systems
// classes.
//
// This file contains the routines that manage higher-level
// functionality. Instruction execution is in a separate file.
//
/* Copyright (c) 1999-2004 by Ethan L. Miller
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
static
char
rcsid
[]
=
"$Id: dlxsim.cc,v 1.16 2004/10/01 18:43:40 elm Exp $"
;
char
rcsDlxsimDate
[]
=
"$Date: 2004/10/01 18:43:40 $"
;
#include
<
stdio
.
h
>
#include
<
errno
.
h
>
#include
<
string
.
h
>
#include
<
ctype
.
h
>
#include
<
stdlib
.
h
>
#include
<
sys
/
time
.
h
>
#include
<
time
.
h
>
#include
<
signal
.
h
>
#include
<
fcntl
.
h
>
#include
"dlx.h"
#include
"dlx-inlines.h"
extern
int
errno
;
char
debug
[
100
];
//----------------------------------------------------------------------
//
// Cpu::Cpu
//
// Create a new CPU.
//
//----------------------------------------------------------------------
Cpu
::
Cpu
(
int
msize
)
:
debugger
(
NULL
)
{
int
i
;
struct
timeval t
;
flags
=
0
;
usElapsed
=
0
;
tickCounter
=
0
;
instrsExecuted
=
0
;
instPerUs
=
1
;
for
(
i
=
0
;
i
<
32
;
i
++
)
{
sreg
[
i
]
=
0
;
ireg
[
i
]
=
0
;
freg
[
i
]
=
0
;
}
SetStatusBit
(
DLX_STATUS_PAGE_TABLE
);
SetStatusBit
(
DLX_STATUS_SYSMODE
);
EnableInterrupts
();
timerInterrupt
=
DLX_TIMER_NOT_ACTIVE
;
memSize
=
msize
;
memory
=
new
uint32
[
msize
/
sizeof
(
uint32
)];
basicBlockStart
=
1
;
// basic block can never start at address 1!
// Initialize the keyboard I/O stuff.
kbdbufferedchars
=
0
;
kbdrpos
=
kbdwpos
=
0
;
kbdcounter
=
0
;
diskIntrTime
=
1e60
;
SetupRawIo
();
gettimeofday
(
&
t
,
(
struct
timezone
*
)
0
);
realElapsed
=
(
double
)
t
.
tv_sec
+
((
double
)
t
.
tv_usec
)
*
1e-6
;
}
//----------------------------------------------------------------------
//
// TraceFile
//
// Open the passed file name for tracing. If the file is NULL,
// open stdout.
//
//----------------------------------------------------------------------
int
Cpu
::
TraceFile
(
char
*
name
)
{
if
((
name
==
NULL
)
||
(
!
strcmp
(
name
,
"-"
)))
{
tracefp
=
stdout
;
return
(
1
);
}
else
if
((
tracefp
=
fopen
(
name
,
"w"
))
==
NULL
)
{
return
(
0
);
}
else
{
return
(
1
);
}
}
//----------------------------------------------------------------------
//
// Cpu::CauseException
//
// Cause an exception. This loads the CAUSE register with the
// exception cause, loads the IAR with the proper pointer, and
// sets things up so that the exception will be taken after the
// current instruction completes.
//
//----------------------------------------------------------------------
int
Cpu
::
CauseException
(
int
excType
)
{
uint32 ivec
;
DBPRINTF
(
't'
,
"Exception being done (cause=0x%x @ pc=0x%x).\n"
,
excType
,
PC
()
-
4
);
ivec
=
GetSreg
(
DLX_SREG_INTRVEC
);
OutputBasicBlock
(
ivec
);
if
(
flags
&
(
DLX_TRACE_INSTRUCTIONS
|
DLX_TRACE_MEMORY
))
{
fprintf
(
tracefp
,
"X %x %x\n"
,
excType
,
PC
()
-
4
);
}
PutSreg
(
DLX_SREG_CAUSE
,
excType
);
// PC has already been incremented, so decrement it first. If this
// is a trap or interrupt, the PC will have already been incremented
// (if necessary) so the IAR points to the next instruction to
// execute.
PutSreg
(
DLX_SREG_IAR
,
PC
()
-
4
);
// Save the current status register
PutSreg
(
DLX_SREG_ISR
,
GetSreg
(
DLX_SREG_STATUS
));
// Save the current value of register 31. This is necessary to give
// the interrupt handler a temporary register that can be used to
// switch to a system stack (rather than user stack)
PutSreg
(
DLX_SREG_IR31
,
GetIreg
(
31
));
// Set the next instruction to be run to be the interrupt vector.
SetPC
(
ivec
);
// Set the status register to be system mode
PutSreg
(
DLX_SREG_STATUS
,
GetSreg
(
DLX_SREG_STATUS
)
|
DLX_STATUS_SYSMODE
);
// Turn off interrupts
DisableInterrupts
();
return
(
1
);
}
//----------------------------------------------------------------------
//
// Cpu::VaddrToPaddr
//
// Read a single word from memory. This involves translating
// the virtual address to a physical address, checking that the
// access is allowed, and ensuring that the address itself is
// valid (ie, aligned). An exception is caused (and 0 returned)
// if the access fails for any reason.
//
//----------------------------------------------------------------------
inline
int
Cpu
::
VaddrToPaddr
(
uint32 vaddr
,
uint32
&
paddr
,
uint32 op
,
uint32 pteflags
)
{
if
((
vaddr
&
0x3
)
!=
0
)
{
CauseException
(
DLX_EXC_ADDRESS
);
return
(
0
);
}
// For system references, physical address is the same
// as virtual address. Also, if no translation bits are set, physical
// address is set to virtual address.
paddr
=
vaddr
;
if
(
UserMode
())
{
// For user mode addresses, translate using
if
(
StatusBit
(
DLX_STATUS_PAGE_TABLE
))
{
uint32 pt1base
,
pt2base
,
pt1pagebits
,
pt2pagebits
;
uint32 pteaddr
;
uint32 offsetinpage
,
entrynum
;
uint32 pagemask
;
DBPRINTF
(
'm'
,
"Translating 0x%x\n"
,
vaddr
);
pt1base
=
GetSreg
(
DLX_SREG_PGTBL_BASE
);
pt1pagebits
=
GetSreg
(
DLX_SREG_PGTBL_BITS
);
pt2pagebits
=
(
pt1pagebits
>>
16
)
&
0xffff
;
pt1pagebits
&=
0xffff
;
pagemask
=
(
1
<<
pt2pagebits
)
-
1
;
offsetinpage
=
vaddr
&
pagemask
;
// Mask off the low bits
vaddr
&=
~
pagemask
;
if
((
entrynum
=
(
vaddr
>>
pt1pagebits
))
>=
GetSreg
(
DLX_SREG_PGTBL_SIZE
))
{
DBPRINTF
(
'm'
,
"Out of range (L1 = %db, L2 = %db size=%d entry=%d)\n"
,
pt1pagebits
,
pt2pagebits
,
GetSreg
(
DLX_SREG_PGTBL_SIZE
),
entrynum
);
CauseException
(
DLX_EXC_ACCESS
);
return
(
0
);
}
pteaddr
=
pt1base
+
4
*
entrynum
;
paddr
=
Memory
(
pteaddr
);
// If the L2 page size is the same as the L1 page size, there's
// no L2 page table!
if
(
pt1pagebits
!=
pt2pagebits
)
{
pt2base
=
paddr
;
if
(
pt2base
==
0
)
{
DBPRINTF
(
'm'
,
"No L2 table at entry %d! (base = 0x%x)\n"
,
entrynum
,
pt1base
);
CauseException
(
DLX_EXC_PAGEFAULT
);
return
(
0
);
}
pteaddr
=
pt2base
+
4
*
((
vaddr
>>
pt2pagebits
)
&
((
1
<<
(
pt1pagebits
-
pt2pagebits
))
-
1
));
paddr
=
Memory
(
pteaddr
);
}
DBPRINTF
(
'M'
,
"Using PTE 0x%08x\n"
,
paddr
);
if
(
!
(
paddr
&
DLX_PTE_VALID
))
{
DBPRINTF
(
'm'
,
"PTE invalid (0x%08x)\n"
,
paddr
);
PutSreg
(
DLX_SREG_FAULT_ADDR
,
vaddr
);
CauseException
(
DLX_EXC_PAGEFAULT
);
return
(
0
);
}
if
(
pteflags
&
(
DLX_PTE_DIRTY
|
DLX_PTE_REFERENCED
))
{
SetMemory
(
pteaddr
,
paddr
|
(
pteflags
&
(
DLX_PTE_DIRTY
|
DLX_PTE_REFERENCED
)));
}
paddr
&=
~
(
pagemask
|
DLX_PTE_MASK
);
paddr
|=
offsetinpage
;
DBPRINTF
(
'm'
,
"0x%x => 0x%x (=%08x) using base1=0x%x/%d, entry %d\n"
,
vaddr
|
offsetinpage
,
paddr
,
Memory
(
paddr
),
pt1base
,
pt1pagebits
,
entrynum
);
// Fall through for address range check
}
else
if
(
StatusBit
(
DLX_STATUS_TLB
))
{
// TLB is fully associative
int
tlbLine
,
gotAddr
=
0
;
uint32 tlbVpage
,
tlbPpage
,
pageSize
,
pageMask
,
entryBits
;
DBPRINTF
(
'm'
,
"Translating addr 0x%x with TLB.\n"
,
vaddr
);
for
(
tlbLine
=
0
;
tlbLine
<
DLX_TLB_NENTRIES
;
tlbLine
++
)
{
GetTlb
(
tlbLine
,
tlbVpage
,
tlbPpage
);
pageSize
=
1
<<
(
tlbPpage
&
DLX_TLB_ENTRY_PAGESIZE_MASK
);
pageMask
=
~
(
pageSize
-
1
);
entryBits
=
tlbVpage
&
DLX_PTE_MASK
;
tlbVpage
&=
pageMask
;
if
((
vaddr
>=
(
tlbVpage
&
pageMask
))
&&
(
vaddr
<
(
tlbVpage
+
pageSize
))
&&
(
entryBits
&
DLX_PTE_VALID
))
{
// Got a match!
gotAddr
=
1
;
break
;
}
}
if
(
!
gotAddr
)
{
DBPRINTF
(
'm'
,
"No TLB entry for vaddr 0x%x.\n"
,
vaddr
);
// Cause a TLB exception if we didn't find the page
PutSreg
(
DLX_SREG_FAULT_ADDR
,
vaddr
);
CauseException
(
DLX_EXC_TLBFAULT
);
return
(
0
);
}
AccessTlb
(
tlbLine
,
DLX_PTE_REFERENCED
|
((
op
==
DLX_MEM_WRITE
)
?
DLX_PTE_DIRTY
:
0
));
paddr
=
(
tlbPpage
&
pageMask
)
|
(
vaddr
&
~
pageMask
);
DBPRINTF
(
'm'
,
"0x%x => 0x%x (=%08x) using tlb entry %d (v=%08x,p=%08x)\n"
,
vaddr
,
paddr
,
Memory
(
paddr
),
tlbLine
,
tlbVpage
,
tlbPpage
);
// Fall through for address range check
}
}
if
((
paddr
<=
memSize
)
||
((
paddr
>=
DLX_IO_BASE
)
&&
(
paddr
<=
(
DLX_IO_BASE
+
DLX_IO_SIZE
))))
{
return
(
1
);
}
else
{
DBPRINTF
(
't'
,
"Illegal system address: 0x%x.\n"
,
vaddr
);
CauseException
(
DLX_EXC_ACCESS
);
return
(
0
);
}
}
//----------------------------------------------------------------------
//
// Cpu::ReadWord
//
// Read a word from memory. This can either be a regular memory
// address or an I/O address.
//
//----------------------------------------------------------------------
int
Cpu
::
ReadWord
(
uint32 vaddr
,
uint32
&
val
,
uint32 op
)
{
uint32 paddr
;
int
i
;
int
done
=
0
;
DBPRINTF
(
'l'
,
"Trying to read virtual address: 0x%x.\n"
,
vaddr
);
if
(
!
VaddrToPaddr
(
vaddr
,
paddr
,
op
,
DLX_PTE_REFERENCED
))
{
return
(
0
);
}
if
(
paddr
<=
memSize
)
{
val
=
Memory
(
paddr
);
}
else
if
((
paddr
>=
DLX_DISK_ADDR_MIN
)
&&
(
paddr
<=
DLX_DISK_ADDR_MAX
))
{
for
(
i
=
0
;
i
<
DLX_DISK_MAX_DISKS
;
i
++
)
{
if
(
paddr
==
DLX_DISK_STATUS
+
(
i
*
0x10
))
{
if
(
disk
[
i
]
!=
NULL
)
{
val
=
disk
[
i
]
->
GetStatus
();
}
else
{
val
=
0
;
}
done
=
1
;
break
;
}
}
if
(
!
done
)
{
DBPRINTF
(
'x'
,
"Illegal disk address: 0x%x.\n"
,
paddr
);