2023-03-13 22:52:27 +01:00
|
|
|
use crate::simulator::translationtable::*;
|
|
|
|
use crate::simulator::machine::*;
|
|
|
|
|
|
|
|
pub struct MMU <'a>{
|
|
|
|
/* Un MMU possède une seule référence vers une table des pages à un instant donné
|
|
|
|
* Cette table est associée au processus courant
|
|
|
|
* Cette référence peut etre mise a jour par exemple lors d'un switchTo
|
|
|
|
*/
|
|
|
|
translationTable : Option<&'a mut TranslationTable>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <'a>MMU <'_>{
|
|
|
|
|
|
|
|
fn create() -> MMU <'a>{
|
|
|
|
|
|
|
|
MMU{
|
|
|
|
translationTable : None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-15 12:17:37 +01:00
|
|
|
pub fn mmu_read_mem(mmu : &mut MMU, machine : &mut Machine, virt_addr : u64, value : &mut u64, size : i32) -> bool {
|
2023-03-15 00:32:58 +01:00
|
|
|
//Pour plus tard eventuellement considerer le boutisme de notre mémoire
|
|
|
|
//Peut etre pas si on fixe cela en BIG ENDIAN (octects poids fort au debut)
|
|
|
|
let mut phy_addr : u64 = 0;
|
|
|
|
let mut phy_addr_double_check : u64 = 0;
|
2023-03-15 12:17:37 +01:00
|
|
|
|
2023-03-15 00:32:58 +01:00
|
|
|
let exc = MMU::translate(mmu, virt_addr, &mut phy_addr, false);
|
2023-03-15 12:17:37 +01:00
|
|
|
|
2023-03-15 00:32:58 +01:00
|
|
|
MMU::translate(mmu, virt_addr, &mut phy_addr_double_check, false);
|
|
|
|
|
2023-03-15 12:17:37 +01:00
|
|
|
match exc {
|
2023-03-23 20:54:05 +01:00
|
|
|
ExceptionType::NoException => {
|
2023-03-15 12:17:37 +01:00
|
|
|
if phy_addr != phy_addr_double_check {
|
|
|
|
//Besoin ici d'une impl pour gestion d'exeption
|
|
|
|
//dans nachos : g-machine->RaiseException(exc, virt_addr);
|
|
|
|
println!("Error from mmu_read_mem :: phy_addr != phy_addr_double_check");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*value = Machine::read_memory(machine, size, phy_addr as usize);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
//Besoin ici d'une impl pour gestion d'exeption
|
|
|
|
//dans nachos : g-machine->RaiseException(exc, virt_addr);
|
2023-03-23 20:54:05 +01:00
|
|
|
println!("Error from mmu_read_mem :: Exception different from NoException");
|
2023-03-15 12:17:37 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-15 00:32:58 +01:00
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2023-03-15 12:17:37 +01:00
|
|
|
pub fn mmu_write_mem(mmu : &mut MMU, machine : &mut Machine, virt_addr : u64, value : u64, size : i32) -> bool {
|
|
|
|
//Pour plus tard eventuellement considerer le boutisme de notre mémoire
|
2023-03-15 00:32:58 +01:00
|
|
|
//Peut etre pas si on fixe cela en BIG ENDIAN (octects poids fort au debut)
|
2023-03-15 12:17:37 +01:00
|
|
|
let mut phy_addr : u64 = 0;
|
|
|
|
let mut phy_addr_double_check : u64 = 0;
|
2023-03-15 00:32:58 +01:00
|
|
|
|
2023-03-15 12:17:37 +01:00
|
|
|
let exc = MMU::translate(mmu, virt_addr, &mut phy_addr, true);
|
2023-03-15 00:32:58 +01:00
|
|
|
|
2023-03-15 12:17:37 +01:00
|
|
|
MMU::translate(mmu, virt_addr, &mut phy_addr_double_check, true);
|
|
|
|
|
|
|
|
match exc {
|
2023-03-23 20:54:05 +01:00
|
|
|
ExceptionType::NoException => {
|
2023-03-15 12:17:37 +01:00
|
|
|
if phy_addr != phy_addr_double_check {
|
|
|
|
//Besoin ici d'une impl pour gestion d'exeption
|
|
|
|
//dans nachos : g-machine->RaiseException(exc, virt_addr);
|
|
|
|
println!("Error from mmu_write_mem :: phy_addr != phy_addr_double_check");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Machine::write_memory(machine, size, phy_addr as usize, value);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
//Besoin ici d'une impl pour gestion d'exeption
|
|
|
|
//dans nachos : g-machine->RaiseException(exc, virt_addr);
|
2023-03-23 20:54:05 +01:00
|
|
|
println!("Error from mmu_write_mem :: Exception different from NoException");
|
2023-03-15 12:17:37 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2023-03-15 00:32:58 +01:00
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn translate(mmu : &mut MMU, virtAddr : u64, physAddr : &mut u64, writing : bool) -> ExceptionType {
|
2023-03-13 22:52:27 +01:00
|
|
|
|
2023-03-14 22:55:48 +01:00
|
|
|
let vpn : u64 = virtAddr/PAGE_SIZE; //virtual page index
|
|
|
|
let offset : u64 = virtAddr%PAGE_SIZE; //adresse intra page
|
2023-03-13 22:52:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-03-15 00:32:58 +01:00
|
|
|
match &mut mmu.translationTable {
|
2023-03-13 22:52:27 +01:00
|
|
|
None => {
|
|
|
|
println!("Error from translate : MMU refers to None (No page Table)");
|
2023-03-23 20:54:05 +01:00
|
|
|
return ExceptionType::AddressErrorException;
|
2023-03-13 22:52:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Some(table_ref) => {
|
|
|
|
|
|
|
|
//On verifie que notre index est valide
|
2023-03-14 22:55:48 +01:00
|
|
|
if vpn >= table_ref.get_max_num_pages(){
|
|
|
|
println!("Error from translate :: index is out of bound");
|
2023-03-23 20:54:05 +01:00
|
|
|
return ExceptionType::AddressErrorException;
|
2023-03-14 22:55:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*Doc nachos dit que ce test sert a savoir si la page est mappée
|
|
|
|
*On teste les droit de lecture ecriture sur cette page
|
|
|
|
*A confirmer avc isabelle
|
|
|
|
*/
|
|
|
|
if !table_ref.get_bit_read(vpn) && !table_ref.get_bit_write(vpn) {
|
|
|
|
println!("Error from translate :: virtual page # {} not mapped",vpn);
|
2023-03-23 20:54:05 +01:00
|
|
|
return ExceptionType::AddressErrorException;
|
2023-03-14 22:55:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//si on souhaite effectuer un acces lecture, on verifie que l'on dispose du droit d'acces sur cette page
|
|
|
|
if writing && !table_ref.get_bit_write(vpn) {
|
|
|
|
println!("Error from translate :: write access on a read only virtual page # {}",vpn);
|
2023-03-23 20:54:05 +01:00
|
|
|
return ExceptionType::AddressErrorException;
|
2023-03-14 22:55:48 +01:00
|
|
|
}
|
2023-03-13 22:52:27 +01:00
|
|
|
|
2023-03-14 22:55:48 +01:00
|
|
|
//if the page is not yet in main memory, run the page fault manager
|
|
|
|
//Page manager not implemented yet
|
|
|
|
if !table_ref.get_bit_valid(vpn){
|
|
|
|
println!("Error from translate :: no valid correspondance");
|
|
|
|
println!("We need to update the page table by raising an exception -> not implemented");
|
|
|
|
|
|
|
|
//Ici il faudra reverifier le bit valid apres intervention du page fault manager
|
2023-03-23 20:54:05 +01:00
|
|
|
return ExceptionType::AddressErrorException;
|
2023-03-13 22:52:27 +01:00
|
|
|
}
|
|
|
|
|
2023-03-14 22:55:48 +01:00
|
|
|
//Make sure that the physical adress is correct
|
2023-03-15 00:32:58 +01:00
|
|
|
if table_ref.get_physical_page(vpn) < 0 || table_ref.get_physical_page(vpn) >= (NUM_PHY_PAGE as i32) {
|
|
|
|
println!("Error from translate :: no valid correspondance");
|
2023-03-23 20:54:05 +01:00
|
|
|
return ExceptionType::BusErrorException;
|
2023-03-15 00:32:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//Set U/M bits to 1
|
|
|
|
if writing {
|
|
|
|
table_ref.set_bit_M(vpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
table_ref.set_bit_U(vpn);
|
|
|
|
|
|
|
|
//on se permet ici la conversion du champs physical_page de i32 vers u64
|
|
|
|
//si cette valeur avait été signée, cela aurait été detecté juste au dessus, renvoyant une BUSERROR_EXCEPTION
|
|
|
|
*physAddr = (table_ref.get_physical_page(vpn) as u64)*PAGE_SIZE + offset;
|
2023-03-13 22:52:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-23 20:54:05 +01:00
|
|
|
ExceptionType::NoException
|
2023-03-13 22:52:27 +01:00
|
|
|
}
|
|
|
|
}
|