From 2a8b141d156de54eab867be3bc39ccc706db7ec3 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Sun, 12 May 2024 11:06:34 +0000 Subject: [PATCH 01/46] Add: file configuration for JSON YAMLTOML and in-line --- Cargo.toml | 5 ++ configuration.rs | 140 +++++++++++++++++++++++++++++++++++++++++++++++ test.json | 17 ++++++ 3 files changed, 162 insertions(+) create mode 100644 configuration.rs create mode 100644 test.json diff --git a/Cargo.toml b/Cargo.toml index 8182d8f..a272e39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,8 @@ license = "GPL-3.0" authors = ["Théo Abel "] # todo: add other contributors [dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.9.34" +toml = "0.8.12" +serde_json = "1.0" +serde-xml-rs = "0.6" \ No newline at end of file diff --git a/configuration.rs b/configuration.rs new file mode 100644 index 0000000..5723b5a --- /dev/null +++ b/configuration.rs @@ -0,0 +1,140 @@ +use serde::{Serialize, Deserialize}; +use std::fs; +use std::error::Error; +use std::env; + +/// Represents the main configuration for a machine. +/// +/// Fields: +/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. +/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. +/// - `dumpfile`: Optional string specifying the path to a dump file. +/// - `outfile`: Optional string specifying the path to an output file. +/// +/// Description: +/// - This struct is used to parse and hold the configuration data of a machine from various file formats. +/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. +/// +/// Purpose: +/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. +/// +/// Technical Explanation: +/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. +/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. +#[derive(Debug, Serialize, Deserialize)] +struct MachineConfig { + mmu_mode: Option, + memspaces: Vec, + dumpfile: Option, + outfile: Option, +} + +/// Defines a memory space with a type and address range. +#[derive(Serialize, Deserialize, Debug)] +struct MemorySpace { + space_type: SpaceType, + start_address: u64, + end_address: u64, +} + +/// Enumerates types of memory spaces. +#[derive(Serialize, Deserialize, Debug)] +enum SpaceType { + RAM, + ROM, +} + +/// Enumerates RISC-V MMU modes. +#[derive(Debug, Serialize, Deserialize)] +enum RiscVMMUMode { + SV39, + SV48, +} + +/// Loads configuration from a specified file. +/// +/// Args: +/// - `file_path`: The path to the configuration file. +/// +/// Returns: +/// - A `Result` containing `MachineConfig` or an error. +/// +/// Description: +/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. +/// +/// Purpose: +/// - To abstract the details of loading and parsing configuration files into a single reusable function. +/// +/// Technical Explanation: +/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. +/// - It handles JSON, YAML, TOML, and XML formats. +/// +/// Example: +/// ```rust +/// let config = load_config("config.json").unwrap(); +/// println!("{:?}", config); +/// ``` +fn load_config(file_path: &str) -> Result> { + let config_str = fs::read_to_string(file_path)?; + let config: MachineConfig = match file_path.rsplit('.').next().ok_or("No file extension found")? { + "json" => serde_json::from_str(&config_str)?, + "yaml" => serde_yaml::from_str(&config_str)?, + "toml" => toml::from_str(&config_str)?, + "xml" => serde_xml_rs::from_str(&config_str)?, + _ => return Err("Unsupported file format".into()), + }; + Ok(config) +} + +/// Main function demonstrating configuration loading and usage. +/// +/// Example: +/// - This example loads a configuration from a JSON file and demonstrates how to manually convert the `mmu_mode`. +fn main() -> Result<(), Box> { + // Collect command line arguments + let args: Vec = env::args().collect(); + // Check if a file path is provided + if args.len() < 2 { + eprintln!("Usage: {} ", args[0]); + std::process::exit(1); + } + // The file path is the second argument + let config_path = &args[1]; + // Output the path for debugging purposes + println!("Loading configuration from: {}", config_path); + // Attempt to load the configuration + let file_conf = load_config(config_path)?; + // Output the loaded configuration for verification + println!("Loaded Configuration: {:#?}", file_conf); + + let mmu_mode: Option = match file_conf.mmu_mode { + Some(ref mode) => match mode.as_str() { + "SV39" => Some(RiscVMMUMode::SV39), + "SV48" => Some(RiscVMMUMode::SV48), + _ => None, + }, + None => None, + }; + let inline_conf = MachineConfig { + mmu_mode: Some("SV39".to_string()), + memspaces: vec![ + MemorySpace { + space_type: SpaceType::RAM, + start_address: 0x0000000080000000, + end_address: 0x000000017fffffff, + }, + MemorySpace { + space_type: SpaceType::ROM, + start_address: 0x0000000000000000, + end_address: 0x0000000000011fff, + }, + ], + dumpfile: Some("dump.raw".to_string()), + outfile: Some("output.txt".to_string()), + }; + // Output the loaded configuration and the manually converted MMU mode. + println!("File-based Configuration: {:#?}", file_conf); + println!("MMU Mode: {:?}", mmu_mode); + println!("Inline Configuration: {:#?}", inline_conf); + Ok(()) +} diff --git a/test.json b/test.json new file mode 100644 index 0000000..84431bf --- /dev/null +++ b/test.json @@ -0,0 +1,17 @@ +{ + "mmu_mode": "SV39", + "memspaces": [ + { + "space_type": "RAM", + "start_address": 34359738368, + "end_address": 103079215103 + }, + { + "space_type": "ROM", + "start_address": 0, + "end_address": 73727 + } + ], + "dumpfile": "example_dump.raw", + "outfile": "example_output.txt" +} From d03e0ad47b4842d43b0150a43bb7d43589624a8d Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Sun, 12 May 2024 11:09:27 +0000 Subject: [PATCH 02/46] Delete configuration.rs --- configuration.rs | 140 ----------------------------------------------- 1 file changed, 140 deletions(-) delete mode 100644 configuration.rs diff --git a/configuration.rs b/configuration.rs deleted file mode 100644 index 5723b5a..0000000 --- a/configuration.rs +++ /dev/null @@ -1,140 +0,0 @@ -use serde::{Serialize, Deserialize}; -use std::fs; -use std::error::Error; -use std::env; - -/// Represents the main configuration for a machine. -/// -/// Fields: -/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. -/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. -/// - `dumpfile`: Optional string specifying the path to a dump file. -/// - `outfile`: Optional string specifying the path to an output file. -/// -/// Description: -/// - This struct is used to parse and hold the configuration data of a machine from various file formats. -/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. -/// -/// Purpose: -/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. -/// -/// Technical Explanation: -/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. -/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. -#[derive(Debug, Serialize, Deserialize)] -struct MachineConfig { - mmu_mode: Option, - memspaces: Vec, - dumpfile: Option, - outfile: Option, -} - -/// Defines a memory space with a type and address range. -#[derive(Serialize, Deserialize, Debug)] -struct MemorySpace { - space_type: SpaceType, - start_address: u64, - end_address: u64, -} - -/// Enumerates types of memory spaces. -#[derive(Serialize, Deserialize, Debug)] -enum SpaceType { - RAM, - ROM, -} - -/// Enumerates RISC-V MMU modes. -#[derive(Debug, Serialize, Deserialize)] -enum RiscVMMUMode { - SV39, - SV48, -} - -/// Loads configuration from a specified file. -/// -/// Args: -/// - `file_path`: The path to the configuration file. -/// -/// Returns: -/// - A `Result` containing `MachineConfig` or an error. -/// -/// Description: -/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. -/// -/// Purpose: -/// - To abstract the details of loading and parsing configuration files into a single reusable function. -/// -/// Technical Explanation: -/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. -/// - It handles JSON, YAML, TOML, and XML formats. -/// -/// Example: -/// ```rust -/// let config = load_config("config.json").unwrap(); -/// println!("{:?}", config); -/// ``` -fn load_config(file_path: &str) -> Result> { - let config_str = fs::read_to_string(file_path)?; - let config: MachineConfig = match file_path.rsplit('.').next().ok_or("No file extension found")? { - "json" => serde_json::from_str(&config_str)?, - "yaml" => serde_yaml::from_str(&config_str)?, - "toml" => toml::from_str(&config_str)?, - "xml" => serde_xml_rs::from_str(&config_str)?, - _ => return Err("Unsupported file format".into()), - }; - Ok(config) -} - -/// Main function demonstrating configuration loading and usage. -/// -/// Example: -/// - This example loads a configuration from a JSON file and demonstrates how to manually convert the `mmu_mode`. -fn main() -> Result<(), Box> { - // Collect command line arguments - let args: Vec = env::args().collect(); - // Check if a file path is provided - if args.len() < 2 { - eprintln!("Usage: {} ", args[0]); - std::process::exit(1); - } - // The file path is the second argument - let config_path = &args[1]; - // Output the path for debugging purposes - println!("Loading configuration from: {}", config_path); - // Attempt to load the configuration - let file_conf = load_config(config_path)?; - // Output the loaded configuration for verification - println!("Loaded Configuration: {:#?}", file_conf); - - let mmu_mode: Option = match file_conf.mmu_mode { - Some(ref mode) => match mode.as_str() { - "SV39" => Some(RiscVMMUMode::SV39), - "SV48" => Some(RiscVMMUMode::SV48), - _ => None, - }, - None => None, - }; - let inline_conf = MachineConfig { - mmu_mode: Some("SV39".to_string()), - memspaces: vec![ - MemorySpace { - space_type: SpaceType::RAM, - start_address: 0x0000000080000000, - end_address: 0x000000017fffffff, - }, - MemorySpace { - space_type: SpaceType::ROM, - start_address: 0x0000000000000000, - end_address: 0x0000000000011fff, - }, - ], - dumpfile: Some("dump.raw".to_string()), - outfile: Some("output.txt".to_string()), - }; - // Output the loaded configuration and the manually converted MMU mode. - println!("File-based Configuration: {:#?}", file_conf); - println!("MMU Mode: {:?}", mmu_mode); - println!("Inline Configuration: {:#?}", inline_conf); - Ok(()) -} From 2ebf899e136c824bfdf703bf7164482c8d6f60dc Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Sun, 12 May 2024 11:09:45 +0000 Subject: [PATCH 03/46] Delete test.json --- test.json | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 test.json diff --git a/test.json b/test.json deleted file mode 100644 index 84431bf..0000000 --- a/test.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "mmu_mode": "SV39", - "memspaces": [ - { - "space_type": "RAM", - "start_address": 34359738368, - "end_address": 103079215103 - }, - { - "space_type": "ROM", - "start_address": 0, - "end_address": 73727 - } - ], - "dumpfile": "example_dump.raw", - "outfile": "example_output.txt" -} From 36763c7b02525f6ae5dcb4b666dcbc8ca4a0e848 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Sun, 12 May 2024 11:11:24 +0000 Subject: [PATCH 04/46] re-upload file at the right place --- src/configuration.rs | 140 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/configuration.rs diff --git a/src/configuration.rs b/src/configuration.rs new file mode 100644 index 0000000..5723b5a --- /dev/null +++ b/src/configuration.rs @@ -0,0 +1,140 @@ +use serde::{Serialize, Deserialize}; +use std::fs; +use std::error::Error; +use std::env; + +/// Represents the main configuration for a machine. +/// +/// Fields: +/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. +/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. +/// - `dumpfile`: Optional string specifying the path to a dump file. +/// - `outfile`: Optional string specifying the path to an output file. +/// +/// Description: +/// - This struct is used to parse and hold the configuration data of a machine from various file formats. +/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. +/// +/// Purpose: +/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. +/// +/// Technical Explanation: +/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. +/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. +#[derive(Debug, Serialize, Deserialize)] +struct MachineConfig { + mmu_mode: Option, + memspaces: Vec, + dumpfile: Option, + outfile: Option, +} + +/// Defines a memory space with a type and address range. +#[derive(Serialize, Deserialize, Debug)] +struct MemorySpace { + space_type: SpaceType, + start_address: u64, + end_address: u64, +} + +/// Enumerates types of memory spaces. +#[derive(Serialize, Deserialize, Debug)] +enum SpaceType { + RAM, + ROM, +} + +/// Enumerates RISC-V MMU modes. +#[derive(Debug, Serialize, Deserialize)] +enum RiscVMMUMode { + SV39, + SV48, +} + +/// Loads configuration from a specified file. +/// +/// Args: +/// - `file_path`: The path to the configuration file. +/// +/// Returns: +/// - A `Result` containing `MachineConfig` or an error. +/// +/// Description: +/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. +/// +/// Purpose: +/// - To abstract the details of loading and parsing configuration files into a single reusable function. +/// +/// Technical Explanation: +/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. +/// - It handles JSON, YAML, TOML, and XML formats. +/// +/// Example: +/// ```rust +/// let config = load_config("config.json").unwrap(); +/// println!("{:?}", config); +/// ``` +fn load_config(file_path: &str) -> Result> { + let config_str = fs::read_to_string(file_path)?; + let config: MachineConfig = match file_path.rsplit('.').next().ok_or("No file extension found")? { + "json" => serde_json::from_str(&config_str)?, + "yaml" => serde_yaml::from_str(&config_str)?, + "toml" => toml::from_str(&config_str)?, + "xml" => serde_xml_rs::from_str(&config_str)?, + _ => return Err("Unsupported file format".into()), + }; + Ok(config) +} + +/// Main function demonstrating configuration loading and usage. +/// +/// Example: +/// - This example loads a configuration from a JSON file and demonstrates how to manually convert the `mmu_mode`. +fn main() -> Result<(), Box> { + // Collect command line arguments + let args: Vec = env::args().collect(); + // Check if a file path is provided + if args.len() < 2 { + eprintln!("Usage: {} ", args[0]); + std::process::exit(1); + } + // The file path is the second argument + let config_path = &args[1]; + // Output the path for debugging purposes + println!("Loading configuration from: {}", config_path); + // Attempt to load the configuration + let file_conf = load_config(config_path)?; + // Output the loaded configuration for verification + println!("Loaded Configuration: {:#?}", file_conf); + + let mmu_mode: Option = match file_conf.mmu_mode { + Some(ref mode) => match mode.as_str() { + "SV39" => Some(RiscVMMUMode::SV39), + "SV48" => Some(RiscVMMUMode::SV48), + _ => None, + }, + None => None, + }; + let inline_conf = MachineConfig { + mmu_mode: Some("SV39".to_string()), + memspaces: vec![ + MemorySpace { + space_type: SpaceType::RAM, + start_address: 0x0000000080000000, + end_address: 0x000000017fffffff, + }, + MemorySpace { + space_type: SpaceType::ROM, + start_address: 0x0000000000000000, + end_address: 0x0000000000011fff, + }, + ], + dumpfile: Some("dump.raw".to_string()), + outfile: Some("output.txt".to_string()), + }; + // Output the loaded configuration and the manually converted MMU mode. + println!("File-based Configuration: {:#?}", file_conf); + println!("MMU Mode: {:?}", mmu_mode); + println!("Inline Configuration: {:#?}", inline_conf); + Ok(()) +} From d26347efdd211afe6726cf77043872cb38a16d4d Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Sun, 12 May 2024 11:12:19 +0000 Subject: [PATCH 05/46] upload json to test configuration parser --- tests/test.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/test.json diff --git a/tests/test.json b/tests/test.json new file mode 100644 index 0000000..84431bf --- /dev/null +++ b/tests/test.json @@ -0,0 +1,17 @@ +{ + "mmu_mode": "SV39", + "memspaces": [ + { + "space_type": "RAM", + "start_address": 34359738368, + "end_address": 103079215103 + }, + { + "space_type": "ROM", + "start_address": 0, + "end_address": 73727 + } + ], + "dumpfile": "example_dump.raw", + "outfile": "example_output.txt" +} From c25d6ce69c969c84b336c983f8412982d3522339 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Thu, 16 May 2024 09:54:58 +0200 Subject: [PATCH 06/46] Update configuration.rs : comment example main to allow merge without conflict --- src/configuration.rs | 82 ++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/configuration.rs b/src/configuration.rs index 5723b5a..34cdc1d 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -90,51 +90,51 @@ fn load_config(file_path: &str) -> Result> { /// /// Example: /// - This example loads a configuration from a JSON file and demonstrates how to manually convert the `mmu_mode`. -fn main() -> Result<(), Box> { +/// fn main() -> Result<(), Box> { // Collect command line arguments - let args: Vec = env::args().collect(); +/// let args: Vec = env::args().collect(); // Check if a file path is provided - if args.len() < 2 { - eprintln!("Usage: {} ", args[0]); - std::process::exit(1); - } +/// if args.len() < 2 { +/// eprintln!("Usage: {} ", args[0]); +/// std::process::exit(1); +/// } // The file path is the second argument - let config_path = &args[1]; +/// let config_path = &args[1]; // Output the path for debugging purposes - println!("Loading configuration from: {}", config_path); +/// println!("Loading configuration from: {}", config_path); // Attempt to load the configuration - let file_conf = load_config(config_path)?; +/// let file_conf = load_config(config_path)?; // Output the loaded configuration for verification - println!("Loaded Configuration: {:#?}", file_conf); - - let mmu_mode: Option = match file_conf.mmu_mode { - Some(ref mode) => match mode.as_str() { - "SV39" => Some(RiscVMMUMode::SV39), - "SV48" => Some(RiscVMMUMode::SV48), - _ => None, - }, - None => None, - }; - let inline_conf = MachineConfig { - mmu_mode: Some("SV39".to_string()), - memspaces: vec![ - MemorySpace { - space_type: SpaceType::RAM, - start_address: 0x0000000080000000, - end_address: 0x000000017fffffff, - }, - MemorySpace { - space_type: SpaceType::ROM, - start_address: 0x0000000000000000, - end_address: 0x0000000000011fff, - }, - ], - dumpfile: Some("dump.raw".to_string()), - outfile: Some("output.txt".to_string()), - }; +/// println!("Loaded Configuration: {:#?}", file_conf); +/// +/// let mmu_mode: Option = match file_conf.mmu_mode { +/// Some(ref mode) => match mode.as_str() { +/// "SV39" => Some(RiscVMMUMode::SV39), +/// "SV48" => Some(RiscVMMUMode::SV48), +/// _ => None, +/// }, +/// None => None, +/// }; +/// let inline_conf = MachineConfig { +/// mmu_mode: Some("SV39".to_string()), +/// memspaces: vec![ +/// MemorySpace { +/// space_type: SpaceType::RAM, +/// start_address: 0x0000000080000000, +/// end_address: 0x000000017fffffff, +/// }, +/// MemorySpace { +/// space_type: SpaceType::ROM, +/// start_address: 0x0000000000000000, +/// end_address: 0x0000000000011fff, +/// }, +/// ], +/// dumpfile: Some("dump.raw".to_string()), +/// outfile: Some("output.txt".to_string()), +/// }; // Output the loaded configuration and the manually converted MMU mode. - println!("File-based Configuration: {:#?}", file_conf); - println!("MMU Mode: {:?}", mmu_mode); - println!("Inline Configuration: {:#?}", inline_conf); - Ok(()) -} +/// println!("File-based Configuration: {:#?}", file_conf); +/// println!("MMU Mode: {:?}", mmu_mode); +/// println!("Inline Configuration: {:#?}", inline_conf); +/// Ok(()) +/// } From bab8ccd5579ffef5880a51ad89c8ebc768dd3742 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Fri, 24 May 2024 10:45:06 +0200 Subject: [PATCH 07/46] Create test.toml --- tests/test.TOML | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/test.TOML diff --git a/tests/test.TOML b/tests/test.TOML new file mode 100644 index 0000000..86d9763 --- /dev/null +++ b/tests/test.TOML @@ -0,0 +1,14 @@ +mmu_mode = "SV39" + +[[memspaces]] +space_type = "RAM" +start_address = 34359738368 +end_address = 103079215103 + +[[memspaces]] +space_type = "ROM" +start_address = 0 +end_address = 73727 + +dumpfile = "example_dump.raw" +outfile = "example_output.txt" From 43fb2e041273150004f638cd0bb4914c2b023769 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Fri, 24 May 2024 10:45:23 +0200 Subject: [PATCH 08/46] Rename test.TOML to test.toml --- tests/{test.TOML => test.toml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test.TOML => test.toml} (100%) diff --git a/tests/test.TOML b/tests/test.toml similarity index 100% rename from tests/test.TOML rename to tests/test.toml From b5171f359834702ac046fe0ed7b79502f0eb2ec2 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Fri, 24 May 2024 10:46:09 +0200 Subject: [PATCH 09/46] Create test.yaml --- tests/test.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/test.yaml diff --git a/tests/test.yaml b/tests/test.yaml new file mode 100644 index 0000000..a87f10b --- /dev/null +++ b/tests/test.yaml @@ -0,0 +1,13 @@ +mmu_mode: "SV39" + +memspaces: + - space_type: "RAM" + start_address: 34359738368 + end_address: 103079215103 + + - space_type: "ROM" + start_address: 0 + end_address: 73727 + +dumpfile: "example_dump.raw" +outfile: "example_output.txt" From 3df6238fd5a4825bcf2bf96a102f5dfd421adc83 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Fri, 24 May 2024 10:47:32 +0200 Subject: [PATCH 10/46] Create test.xml --- tests/test.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/test.xml diff --git a/tests/test.xml b/tests/test.xml new file mode 100644 index 0000000..c5c2364 --- /dev/null +++ b/tests/test.xml @@ -0,0 +1,17 @@ + + SV39 + + + RAM + 34359738368 + 103079215103 + + + ROM + 0 + 73727 + + + example_dump.raw + example_output.txt + From 419c001abe0edd00bbe88c1862a99407de1129df Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Tue, 28 May 2024 11:43:48 +0200 Subject: [PATCH 11/46] Update configuration.rs to handle only toml and use anyhow::Error --- src/configuration.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/configuration.rs b/src/configuration.rs index 34cdc1d..763fd1e 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -74,23 +74,21 @@ enum RiscVMMUMode { /// let config = load_config("config.json").unwrap(); /// println!("{:?}", config); /// ``` -fn load_config(file_path: &str) -> Result> { - let config_str = fs::read_to_string(file_path)?; - let config: MachineConfig = match file_path.rsplit('.').next().ok_or("No file extension found")? { - "json" => serde_json::from_str(&config_str)?, - "yaml" => serde_yaml::from_str(&config_str)?, - "toml" => toml::from_str(&config_str)?, - "xml" => serde_xml_rs::from_str(&config_str)?, - _ => return Err("Unsupported file format".into()), +fn load_config(file_path: &str) -> Result { + let config_str = fs::read_to_string(file_path) + .with_context(|| format!("Failed to read configuration file: {}", file_path))?; + let config: MachineConfig = match file_path.rsplit('.').next().context("No file extension found")? { + "toml" => toml::from_str(&config_str) + .with_context(|| format!("Failed to parse TOML configuration file: {}", file_path))?, + _ => return Err(anyhow::Error::msg(format!("Unsupported file format: {}", file_path))), }; Ok(config) } - /// Main function demonstrating configuration loading and usage. /// /// Example: /// - This example loads a configuration from a JSON file and demonstrates how to manually convert the `mmu_mode`. -/// fn main() -> Result<(), Box> { +/// fn main() -> Result<(), anyhow::Error> { // Collect command line arguments /// let args: Vec = env::args().collect(); // Check if a file path is provided From 1b8dc708ece81dcd608913a6a7257191c4374429 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Tue, 28 May 2024 11:46:33 +0200 Subject: [PATCH 12/46] Update configuration.rs : update documentation --- src/configuration.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/configuration.rs b/src/configuration.rs index 763fd1e..807fd05 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -67,11 +67,11 @@ enum RiscVMMUMode { /// /// Technical Explanation: /// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. -/// - It handles JSON, YAML, TOML, and XML formats. +/// - It handles TOML format. /// /// Example: /// ```rust -/// let config = load_config("config.json").unwrap(); +/// let config = load_config("config.toml").unwrap(); /// println!("{:?}", config); /// ``` fn load_config(file_path: &str) -> Result { From fbeb6fb2dd1a3a5139e8a7bfa8f3ba7eec2a84ac Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Tue, 28 May 2024 11:50:41 +0200 Subject: [PATCH 13/46] Update Cargo.toml --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a272e39..965939b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,11 +13,12 @@ keywords = ["forensics", "memory forensics"] exclude = [".github", "CONTRIBUTING.md", "CODE_OF_CONDUCT.md", "assets"] license = "GPL-3.0" -authors = ["Théo Abel "] # todo: add other contributors +authors = ["Théo Abel "], ["Nathan Dandrimont "] # todo: add other contributors [dependencies] serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9.34" toml = "0.8.12" serde_json = "1.0" -serde-xml-rs = "0.6" \ No newline at end of file +serde-xml-rs = "0.6" +anyhow = "1.0" From 4c2bdb49c24cbf1dc4722c37669330b9c4d3c65f Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Tue, 28 May 2024 11:51:45 +0200 Subject: [PATCH 14/46] Update Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 965939b..7957bfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ keywords = ["forensics", "memory forensics"] exclude = [".github", "CONTRIBUTING.md", "CODE_OF_CONDUCT.md", "assets"] license = "GPL-3.0" -authors = ["Théo Abel "], ["Nathan Dandrimont "] # todo: add other contributors +authors = ["Théo Abel ", "Nathan Dandrimont "] # todo: add other contributors [dependencies] serde = { version = "1.0", features = ["derive"] } From 7522bafd5b3060f4c40633e48ab736ae61a6ce0e Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 10:58:04 +0000 Subject: [PATCH 15/46] fix: after review comment --- Cargo.toml | 3 - src/config_struct.rs | 50 ++++++++++++ src/configuration.rs | 173 +++++++++++++++++------------------------ tests/config/test.toml | 14 ++++ 4 files changed, 136 insertions(+), 104 deletions(-) create mode 100644 src/config_struct.rs create mode 100644 tests/config/test.toml diff --git a/Cargo.toml b/Cargo.toml index 7957bfe..b6deba5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,5 @@ authors = ["Théo Abel ", "Nathan Dandrimont , + pub memspaces: Vec, + pub dumpfile: Option, + pub outfile: Option, +} + +/// Defines a memory space with a type and address range. +#[derive(Serialize, Deserialize, Debug)] +pub struct MemorySpace { + pub space_type: SpaceType, + pub start_address: u64, + pub end_address: u64, +} + +/// Enumerates types of memory spaces. +#[derive(Serialize, Deserialize, Debug)] +pub enum SpaceType { + RAM, + ROM, +} + +/// Enumerates RISC-V MMU modes. +#[derive(Debug, Serialize, Deserialize)] +pub enum RiscVMMUMode { + SV39, + SV48, +} diff --git a/src/configuration.rs b/src/configuration.rs index 807fd05..7abc61d 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,55 +1,10 @@ -use serde::{Serialize, Deserialize}; +mod config_struct; + use std::fs; -use std::error::Error; +use std::path::Path; use std::env; - -/// Represents the main configuration for a machine. -/// -/// Fields: -/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. -/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. -/// - `dumpfile`: Optional string specifying the path to a dump file. -/// - `outfile`: Optional string specifying the path to an output file. -/// -/// Description: -/// - This struct is used to parse and hold the configuration data of a machine from various file formats. -/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. -/// -/// Purpose: -/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. -/// -/// Technical Explanation: -/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. -/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. -#[derive(Debug, Serialize, Deserialize)] -struct MachineConfig { - mmu_mode: Option, - memspaces: Vec, - dumpfile: Option, - outfile: Option, -} - -/// Defines a memory space with a type and address range. -#[derive(Serialize, Deserialize, Debug)] -struct MemorySpace { - space_type: SpaceType, - start_address: u64, - end_address: u64, -} - -/// Enumerates types of memory spaces. -#[derive(Serialize, Deserialize, Debug)] -enum SpaceType { - RAM, - ROM, -} - -/// Enumerates RISC-V MMU modes. -#[derive(Debug, Serialize, Deserialize)] -enum RiscVMMUMode { - SV39, - SV48, -} +use anyhow::{Result, Context}; +use crate::config_struct::{MachineConfig, MemorySpace, SpaceType, RiscVMMUMode}; /// Loads configuration from a specified file. /// @@ -74,65 +29,81 @@ enum RiscVMMUMode { /// let config = load_config("config.toml").unwrap(); /// println!("{:?}", config); /// ``` -fn load_config(file_path: &str) -> Result { +pub fn load_config(file_path: &Path) -> Result { let config_str = fs::read_to_string(file_path) - .with_context(|| format!("Failed to read configuration file: {}", file_path))?; - let config: MachineConfig = match file_path.rsplit('.').next().context("No file extension found")? { - "toml" => toml::from_str(&config_str) - .with_context(|| format!("Failed to parse TOML configuration file: {}", file_path))?, - _ => return Err(anyhow::Error::msg(format!("Unsupported file format: {}", file_path))), + .with_context(|| format!("Failed to read configuration file: {:?}", file_path))?; + let mut config: MachineConfig = match file_path.extension().and_then(|s| s.to_str()) { + Some("toml") => toml::from_str(&config_str) + .with_context(|| format!("Failed to parse TOML configuration file: {:?}", file_path))?, + _ => return Err(anyhow::anyhow!("Unsupported file format: {:?}", file_path)), }; + validate_config(&config)?; Ok(config) } -/// Main function demonstrating configuration loading and usage. +/// Validates the contents of the configuration. /// -/// Example: -/// - This example loads a configuration from a JSON file and demonstrates how to manually convert the `mmu_mode`. -/// fn main() -> Result<(), anyhow::Error> { +/// Args: +/// - `config`: The configuration to validate. +/// +/// Returns: +/// - A `Result` indicating whether the validation was successful. +pub fn validate_config(config: &MachineConfig) -> Result<()> { + if let Some(ref mode) = config.mmu_mode { + match mode.as_str() { + "SV39" | "SV48" => Ok(()), + _ => Err(anyhow::anyhow!("Invalid MMU mode: {}", mode)), + } + } else { + Ok(()) + } +} + +fn main() -> Result<()> { // Collect command line arguments -/// let args: Vec = env::args().collect(); + let args: Vec = env::args().collect(); // Check if a file path is provided -/// if args.len() < 2 { -/// eprintln!("Usage: {} ", args[0]); -/// std::process::exit(1); -/// } + if args.len() < 2 { + eprintln!("Usage: {} ", args[0]); + std::process::exit(1); + } // The file path is the second argument -/// let config_path = &args[1]; + let config_path = Path::new(&args[1]); // Output the path for debugging purposes -/// println!("Loading configuration from: {}", config_path); + println!("Loading configuration from: {:?}", config_path); // Attempt to load the configuration -/// let file_conf = load_config(config_path)?; + let file_conf = load_config(config_path)?; // Output the loaded configuration for verification -/// println!("Loaded Configuration: {:#?}", file_conf); -/// -/// let mmu_mode: Option = match file_conf.mmu_mode { -/// Some(ref mode) => match mode.as_str() { -/// "SV39" => Some(RiscVMMUMode::SV39), -/// "SV48" => Some(RiscVMMUMode::SV48), -/// _ => None, -/// }, -/// None => None, -/// }; -/// let inline_conf = MachineConfig { -/// mmu_mode: Some("SV39".to_string()), -/// memspaces: vec![ -/// MemorySpace { -/// space_type: SpaceType::RAM, -/// start_address: 0x0000000080000000, -/// end_address: 0x000000017fffffff, -/// }, -/// MemorySpace { -/// space_type: SpaceType::ROM, -/// start_address: 0x0000000000000000, -/// end_address: 0x0000000000011fff, -/// }, -/// ], -/// dumpfile: Some("dump.raw".to_string()), -/// outfile: Some("output.txt".to_string()), -/// }; - // Output the loaded configuration and the manually converted MMU mode. -/// println!("File-based Configuration: {:#?}", file_conf); -/// println!("MMU Mode: {:?}", mmu_mode); -/// println!("Inline Configuration: {:#?}", inline_conf); -/// Ok(()) -/// } + println!("Loaded Configuration: {:#?}", file_conf); + + // Manually convert `mmu_mode` to `RiscVMMUMode` + let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { + Some("SV39") => Some(RiscVMMUMode::SV39), + Some("SV48") => Some(RiscVMMUMode::SV48), + _ => None, + }; + + // Inline configuration example + let inline_conf = MachineConfig { + mmu_mode: Some("SV39".to_string()), + memspaces: vec![ + MemorySpace { + space_type: SpaceType::RAM, + start_address: 0x0000000080000000, + end_address: 0x000000017fffffff, + }, + MemorySpace { + space_type: SpaceType::ROM, + start_address: 0x0000000000000000, + end_address: 0x0000000000011fff, + }, + ], + dumpfile: Some("dump.raw".to_string()), + outfile: Some("output.txt".to_string()), + }; + + // Output the loaded configuration and the manually converted MMU mode + println!("File-based Configuration: {:#?}", file_conf); + println!("MMU Mode: {:?}", mmu_mode); + println!("Inline Configuration: {:#?}", inline_conf); + Ok(()) +} diff --git a/tests/config/test.toml b/tests/config/test.toml new file mode 100644 index 0000000..86d9763 --- /dev/null +++ b/tests/config/test.toml @@ -0,0 +1,14 @@ +mmu_mode = "SV39" + +[[memspaces]] +space_type = "RAM" +start_address = 34359738368 +end_address = 103079215103 + +[[memspaces]] +space_type = "ROM" +start_address = 0 +end_address = 73727 + +dumpfile = "example_dump.raw" +outfile = "example_output.txt" From 73c30fb76e800faa7a48c65466525dbcd8317b9a Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 11:09:13 +0000 Subject: [PATCH 16/46] add: common traits --- architecture.rs | 0 config_struct.rs | 50 +++++++++++++++++++++ configuration.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++ lib.rs | 2 + utils.rs | 0 5 files changed, 163 insertions(+) create mode 100644 architecture.rs create mode 100644 config_struct.rs create mode 100644 configuration.rs create mode 100644 lib.rs create mode 100644 utils.rs diff --git a/architecture.rs b/architecture.rs new file mode 100644 index 0000000..e69de29 diff --git a/config_struct.rs b/config_struct.rs new file mode 100644 index 0000000..fc42cd6 --- /dev/null +++ b/config_struct.rs @@ -0,0 +1,50 @@ +use serde::{Serialize, Deserialize}; + +/// Represents the main configuration for a machine. +/// +/// Fields: +/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. +/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. +/// - `dumpfile`: Optional string specifying the path to a dump file. +/// - `outfile`: Optional string specifying the path to an output file. +/// +/// Description: +/// - This struct is used to parse and hold the configuration data of a machine from various file formats. +/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. +/// +/// Purpose: +/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. +/// +/// Technical Explanation: +/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. +/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. +/// +#[derive(Serialize, Debug, Deserialize, Clone, Copy, Default)] +pub struct MachineConfig { + pub mmu_mode: Option, + pub memspaces: Vec, + pub dumpfile: Option, + pub outfile: Option, +} + +/// Defines a memory space with a type and address range. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] +pub struct MemorySpace { + pub space_type: SpaceType, + pub start_address: u64, + pub end_address: u64, +} + +/// Enumerates types of memory spaces. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] +pub enum SpaceType { + RAM, + ROM, +} + +/// Enumerates RISC-V MMU modes. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] +pub enum RiscVMMUMode { + SV39, + SV48, +} diff --git a/configuration.rs b/configuration.rs new file mode 100644 index 0000000..fd42fc4 --- /dev/null +++ b/configuration.rs @@ -0,0 +1,111 @@ +mod config_struct; + +use std::fs; +use std::path::Path; +use std::env; +use anyhow::{Result, Context}; +use crate::config_struct::{MachineConfig, MemorySpace, SpaceType, RiscVMMUMode}; + +/// Loads configuration from a specified file. +/// +/// Args: +/// - `file_path`: The path to the configuration file. +/// +/// Returns: +/// - A `Result` containing `MachineConfig` or an error. +/// +/// Description: +/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. +/// +/// Purpose: +/// - To abstract the details of loading and parsing configuration files into a single reusable function. +/// +/// Technical Explanation: +/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. +/// - It handles TOML format. +/// +/// Example: +/// ```rust +/// let config = load_config("config.toml").unwrap(); +/// println!("{:?}", config); +/// ``` +pub fn load_config(file_path: &Path) -> Result { + let config_str = fs::read_to_string(file_path) + .with_context(|| format!("Failed to read configuration file: {:?}", file_path))?; + let mut config: MachineConfig = match file_path.extension().and_then(|s| s.to_str()) { + Some("toml") => toml::from_str(&config_str) + .with_context(|| format!("Failed to parse TOML configuration file: {:?}", file_path))?, + _ => return Err(anyhow::anyhow!("Unsupported file format: {:?}", file_path)), + }; + validate_config(&config)?; + Ok(config) +} +/// Validates the contents of the configuration. +/// +/// Args: +/// - `config`: The configuration to validate. +/// +/// Returns: +/// - A `Result` indicating whether the validation was successful. +pub fn validate_config(config: &MachineConfig) -> Result<()> { + if let Some(ref mode) = config.mmu_mode { + match mode.as_str() { + "SV39" | "SV48" => Ok(()), + _ => Err(anyhow::anyhow!("Invalid MMU mode: {}", mode)), + } + } else { + Ok(()) + } +} + +/// +///fn main() -> Result<()> { +/// //Collect command line arguments +/// let args: Vec = env::args().collect(); +/// // Check if a file path is provided +/// if args.len() < 2 { +/// eprintln!("Usage: {} ", args[0]); +/// std::process::exit(1); +/// } +/// // The file path is the second argument +/// let config_path = Path::new(&args[1]); +/// // Output the path for debugging purposes +/// println!("Loading configuration from: {:?}", config_path); +/// // Attempt to load the configuration +/// let file_conf = load_config(config_path)?; +/// // Output the loaded configuration for verification +/// println!("Loaded Configuration: {:#?}", file_conf); +/// +/// // Manually convert `mmu_mode` to `RiscVMMUMode` +/// let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { +/// Some("SV39") => Some(RiscVMMUMode::SV39), +/// Some("SV48") => Some(RiscVMMUMode::SV48), +/// _ => None, +/// }; +/// +/// // Inline configuration example +/// let inline_conf = MachineConfig { +/// mmu_mode: Some("SV39".to_string()), +/// memspaces: vec![ +/// MemorySpace { +/// space_type: SpaceType::RAM, +/// start_address: 0x0000000080000000, +/// end_address: 0x000000017fffffff, +/// }, +/// MemorySpace { +/// space_type: SpaceType::ROM, +/// start_address: 0x0000000000000000, +/// end_address: 0x0000000000011fff, +/// }, +/// ], +/// dumpfile: Some("dump.raw".to_string()), +/// outfile: Some("output.txt".to_string()), +/// }; +/// +/// // Output the loaded configuration and the manually converted MMU mode +/// println!("File-based Configuration: {:#?}", file_conf); +/// println!("MMU Mode: {:?}", mmu_mode); +/// println!("Inline Configuration: {:#?}", inline_conf); +/// Ok(()) +///} +/// \ No newline at end of file diff --git a/lib.rs b/lib.rs new file mode 100644 index 0000000..6e975b1 --- /dev/null +++ b/lib.rs @@ -0,0 +1,2 @@ +pub mod architecture; +pub mod utils; diff --git a/utils.rs b/utils.rs new file mode 100644 index 0000000..e69de29 From 1c300902c2964f4dcd15423214136d1403f608b1 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:23:13 +0000 Subject: [PATCH 17/46] Delete configuration.rs --- configuration.rs | 111 ----------------------------------------------- 1 file changed, 111 deletions(-) delete mode 100644 configuration.rs diff --git a/configuration.rs b/configuration.rs deleted file mode 100644 index fd42fc4..0000000 --- a/configuration.rs +++ /dev/null @@ -1,111 +0,0 @@ -mod config_struct; - -use std::fs; -use std::path::Path; -use std::env; -use anyhow::{Result, Context}; -use crate::config_struct::{MachineConfig, MemorySpace, SpaceType, RiscVMMUMode}; - -/// Loads configuration from a specified file. -/// -/// Args: -/// - `file_path`: The path to the configuration file. -/// -/// Returns: -/// - A `Result` containing `MachineConfig` or an error. -/// -/// Description: -/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. -/// -/// Purpose: -/// - To abstract the details of loading and parsing configuration files into a single reusable function. -/// -/// Technical Explanation: -/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. -/// - It handles TOML format. -/// -/// Example: -/// ```rust -/// let config = load_config("config.toml").unwrap(); -/// println!("{:?}", config); -/// ``` -pub fn load_config(file_path: &Path) -> Result { - let config_str = fs::read_to_string(file_path) - .with_context(|| format!("Failed to read configuration file: {:?}", file_path))?; - let mut config: MachineConfig = match file_path.extension().and_then(|s| s.to_str()) { - Some("toml") => toml::from_str(&config_str) - .with_context(|| format!("Failed to parse TOML configuration file: {:?}", file_path))?, - _ => return Err(anyhow::anyhow!("Unsupported file format: {:?}", file_path)), - }; - validate_config(&config)?; - Ok(config) -} -/// Validates the contents of the configuration. -/// -/// Args: -/// - `config`: The configuration to validate. -/// -/// Returns: -/// - A `Result` indicating whether the validation was successful. -pub fn validate_config(config: &MachineConfig) -> Result<()> { - if let Some(ref mode) = config.mmu_mode { - match mode.as_str() { - "SV39" | "SV48" => Ok(()), - _ => Err(anyhow::anyhow!("Invalid MMU mode: {}", mode)), - } - } else { - Ok(()) - } -} - -/// -///fn main() -> Result<()> { -/// //Collect command line arguments -/// let args: Vec = env::args().collect(); -/// // Check if a file path is provided -/// if args.len() < 2 { -/// eprintln!("Usage: {} ", args[0]); -/// std::process::exit(1); -/// } -/// // The file path is the second argument -/// let config_path = Path::new(&args[1]); -/// // Output the path for debugging purposes -/// println!("Loading configuration from: {:?}", config_path); -/// // Attempt to load the configuration -/// let file_conf = load_config(config_path)?; -/// // Output the loaded configuration for verification -/// println!("Loaded Configuration: {:#?}", file_conf); -/// -/// // Manually convert `mmu_mode` to `RiscVMMUMode` -/// let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { -/// Some("SV39") => Some(RiscVMMUMode::SV39), -/// Some("SV48") => Some(RiscVMMUMode::SV48), -/// _ => None, -/// }; -/// -/// // Inline configuration example -/// let inline_conf = MachineConfig { -/// mmu_mode: Some("SV39".to_string()), -/// memspaces: vec![ -/// MemorySpace { -/// space_type: SpaceType::RAM, -/// start_address: 0x0000000080000000, -/// end_address: 0x000000017fffffff, -/// }, -/// MemorySpace { -/// space_type: SpaceType::ROM, -/// start_address: 0x0000000000000000, -/// end_address: 0x0000000000011fff, -/// }, -/// ], -/// dumpfile: Some("dump.raw".to_string()), -/// outfile: Some("output.txt".to_string()), -/// }; -/// -/// // Output the loaded configuration and the manually converted MMU mode -/// println!("File-based Configuration: {:#?}", file_conf); -/// println!("MMU Mode: {:?}", mmu_mode); -/// println!("Inline Configuration: {:#?}", inline_conf); -/// Ok(()) -///} -/// \ No newline at end of file From d217116bf348f4a3b3f1e0510feb80d1c444e8b9 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:23:25 +0000 Subject: [PATCH 18/46] Delete lib.rs --- lib.rs | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 lib.rs diff --git a/lib.rs b/lib.rs deleted file mode 100644 index 6e975b1..0000000 --- a/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod architecture; -pub mod utils; From afe999944aeb727233f6c0fd2bc21d630b70d45b Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:23:36 +0000 Subject: [PATCH 19/46] Delete utils.rs --- utils.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 utils.rs diff --git a/utils.rs b/utils.rs deleted file mode 100644 index e69de29..0000000 From 6ab1f481ceb04e1c30c570155cb27b5dc2863224 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:23:49 +0000 Subject: [PATCH 20/46] Delete config_struct.rs --- config_struct.rs | 50 ------------------------------------------------ 1 file changed, 50 deletions(-) delete mode 100644 config_struct.rs diff --git a/config_struct.rs b/config_struct.rs deleted file mode 100644 index fc42cd6..0000000 --- a/config_struct.rs +++ /dev/null @@ -1,50 +0,0 @@ -use serde::{Serialize, Deserialize}; - -/// Represents the main configuration for a machine. -/// -/// Fields: -/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. -/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. -/// - `dumpfile`: Optional string specifying the path to a dump file. -/// - `outfile`: Optional string specifying the path to an output file. -/// -/// Description: -/// - This struct is used to parse and hold the configuration data of a machine from various file formats. -/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. -/// -/// Purpose: -/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. -/// -/// Technical Explanation: -/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. -/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. -/// -#[derive(Serialize, Debug, Deserialize, Clone, Copy, Default)] -pub struct MachineConfig { - pub mmu_mode: Option, - pub memspaces: Vec, - pub dumpfile: Option, - pub outfile: Option, -} - -/// Defines a memory space with a type and address range. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] -pub struct MemorySpace { - pub space_type: SpaceType, - pub start_address: u64, - pub end_address: u64, -} - -/// Enumerates types of memory spaces. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] -pub enum SpaceType { - RAM, - ROM, -} - -/// Enumerates RISC-V MMU modes. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] -pub enum RiscVMMUMode { - SV39, - SV48, -} From 949eeea1c84d94d6239ceca352b2a4969373af9e Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:24:00 +0000 Subject: [PATCH 21/46] Delete architecture.rs --- architecture.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 architecture.rs diff --git a/architecture.rs b/architecture.rs deleted file mode 100644 index e69de29..0000000 From afe955956b2c428375060636fac76e7b7d5677d5 Mon Sep 17 00:00:00 2001 From: Esgr0bar <163046224+Esgr0bar@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:24:37 +0000 Subject: [PATCH 22/46] Add files via upload --- src/config_struct.rs | 8 ++-- src/configuration.rs | 100 ++++++++++++++++++++++--------------------- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/config_struct.rs b/src/config_struct.rs index c259bcd..fc42cd6 100644 --- a/src/config_struct.rs +++ b/src/config_struct.rs @@ -19,7 +19,7 @@ use serde::{Serialize, Deserialize}; /// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. /// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. /// -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Debug, Deserialize, Clone, Copy, Default)] pub struct MachineConfig { pub mmu_mode: Option, pub memspaces: Vec, @@ -28,7 +28,7 @@ pub struct MachineConfig { } /// Defines a memory space with a type and address range. -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] pub struct MemorySpace { pub space_type: SpaceType, pub start_address: u64, @@ -36,14 +36,14 @@ pub struct MemorySpace { } /// Enumerates types of memory spaces. -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] pub enum SpaceType { RAM, ROM, } /// Enumerates RISC-V MMU modes. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] pub enum RiscVMMUMode { SV39, SV48, diff --git a/src/configuration.rs b/src/configuration.rs index 7abc61d..fd42fc4 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -58,52 +58,54 @@ pub fn validate_config(config: &MachineConfig) -> Result<()> { } } -fn main() -> Result<()> { - // Collect command line arguments - let args: Vec = env::args().collect(); - // Check if a file path is provided - if args.len() < 2 { - eprintln!("Usage: {} ", args[0]); - std::process::exit(1); - } - // The file path is the second argument - let config_path = Path::new(&args[1]); - // Output the path for debugging purposes - println!("Loading configuration from: {:?}", config_path); - // Attempt to load the configuration - let file_conf = load_config(config_path)?; - // Output the loaded configuration for verification - println!("Loaded Configuration: {:#?}", file_conf); - - // Manually convert `mmu_mode` to `RiscVMMUMode` - let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { - Some("SV39") => Some(RiscVMMUMode::SV39), - Some("SV48") => Some(RiscVMMUMode::SV48), - _ => None, - }; - - // Inline configuration example - let inline_conf = MachineConfig { - mmu_mode: Some("SV39".to_string()), - memspaces: vec![ - MemorySpace { - space_type: SpaceType::RAM, - start_address: 0x0000000080000000, - end_address: 0x000000017fffffff, - }, - MemorySpace { - space_type: SpaceType::ROM, - start_address: 0x0000000000000000, - end_address: 0x0000000000011fff, - }, - ], - dumpfile: Some("dump.raw".to_string()), - outfile: Some("output.txt".to_string()), - }; - - // Output the loaded configuration and the manually converted MMU mode - println!("File-based Configuration: {:#?}", file_conf); - println!("MMU Mode: {:?}", mmu_mode); - println!("Inline Configuration: {:#?}", inline_conf); - Ok(()) -} +/// +///fn main() -> Result<()> { +/// //Collect command line arguments +/// let args: Vec = env::args().collect(); +/// // Check if a file path is provided +/// if args.len() < 2 { +/// eprintln!("Usage: {} ", args[0]); +/// std::process::exit(1); +/// } +/// // The file path is the second argument +/// let config_path = Path::new(&args[1]); +/// // Output the path for debugging purposes +/// println!("Loading configuration from: {:?}", config_path); +/// // Attempt to load the configuration +/// let file_conf = load_config(config_path)?; +/// // Output the loaded configuration for verification +/// println!("Loaded Configuration: {:#?}", file_conf); +/// +/// // Manually convert `mmu_mode` to `RiscVMMUMode` +/// let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { +/// Some("SV39") => Some(RiscVMMUMode::SV39), +/// Some("SV48") => Some(RiscVMMUMode::SV48), +/// _ => None, +/// }; +/// +/// // Inline configuration example +/// let inline_conf = MachineConfig { +/// mmu_mode: Some("SV39".to_string()), +/// memspaces: vec![ +/// MemorySpace { +/// space_type: SpaceType::RAM, +/// start_address: 0x0000000080000000, +/// end_address: 0x000000017fffffff, +/// }, +/// MemorySpace { +/// space_type: SpaceType::ROM, +/// start_address: 0x0000000000000000, +/// end_address: 0x0000000000011fff, +/// }, +/// ], +/// dumpfile: Some("dump.raw".to_string()), +/// outfile: Some("output.txt".to_string()), +/// }; +/// +/// // Output the loaded configuration and the manually converted MMU mode +/// println!("File-based Configuration: {:#?}", file_conf); +/// println!("MMU Mode: {:?}", mmu_mode); +/// println!("Inline Configuration: {:#?}", inline_conf); +/// Ok(()) +///} +/// \ No newline at end of file From 8aa0b5923c959b20adacdc5b148ab0dcd1a176ee Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:07:19 +0200 Subject: [PATCH 23/46] feat: added some generic traits/structs, started configuration refactor --- src/architecture.rs | 2 + src/architecture/generic.rs | 69 ++++++++++++++++ src/architecture/riscv.rs | 0 src/config_struct.rs | 50 ------------ src/configuration.rs | 111 ------------------------- src/utils.rs | 1 + src/utils/config_struct.rs | 1 + src/utils/configuration.rs | 159 ++++++++++++++++++++++++++++++++++++ 8 files changed, 232 insertions(+), 161 deletions(-) create mode 100644 src/architecture/generic.rs create mode 100644 src/architecture/riscv.rs delete mode 100644 src/config_struct.rs delete mode 100644 src/configuration.rs create mode 100644 src/utils/config_struct.rs create mode 100644 src/utils/configuration.rs diff --git a/src/architecture.rs b/src/architecture.rs index e69de29..50acd74 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -0,0 +1,2 @@ +pub mod generic; +pub mod riscv; diff --git a/src/architecture/generic.rs b/src/architecture/generic.rs new file mode 100644 index 0000000..65c5205 --- /dev/null +++ b/src/architecture/generic.rs @@ -0,0 +1,69 @@ +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use std::hash; + +// MemoryRegion +// CPU +// CPURegister +// PageTableEntry +// PageTable +// RadixTree +// VirtualAddressSpace +// PhysicalAddressSpace +// MMU +// Machine + +/// Enumerates types of memory regions. +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub enum MemoryRegionType { + RAM, + ROM, +} + +impl Default for MemoryRegionType { + fn default() -> Self { + MemoryRegionType::RAM + } +} + +/// Represents a memory region with a start and end address. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] +pub struct MemoryRegion { + pub _type: MemoryRegionType, + pub start_address: u64, + pub end_address: u64, +} + +/// Represents a CPU register with a value. +/// Depending on the architecture, the *validity* changes. +pub trait CPURegister { + type Value: hash::Hash + Eq + Copy + Default; + + fn is_valid() -> Result; +} + +/// Represents a page table entry with an address and flags. +/// It holds the mapping between a virtual address of a page and the address of a physical frame. +/// There is also auxiliary information about the page such as a present bit, a dirty or modified bit, +/// address space or process ID information, amongst others. +pub trait PageTableEntry { + type Address: hash::Hash + Eq + Copy + Default; + type Flags: hash::Hash + Eq + Copy + Default; + + fn is_dirty() -> bool; + fn is_accessed() -> bool; + fn is_global() -> bool; + fn is_readable() -> bool; + fn is_writable() -> bool; + fn is_executable() -> bool; +} + +/// Represents a page table with entries. +/// It is a data structure used in a virtual memory system to manage the mapping between virtual addresses and physical addresses. +/// It is used to translate virtual addresses to physical addresses and to manage the memory permissions of the pages. +/// It is also used to store additional information about the pages, such as the status of the page, the address space or process ID, amongst others. +pub trait PageTable { + type Entries: hash::Hash + Eq + Copy + Default + PageTableEntry; + + // fn apply_on_entries(function: FnMut(PageTableEntry) -> Vec ) -> ? // to be defined +} diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/config_struct.rs b/src/config_struct.rs deleted file mode 100644 index fc42cd6..0000000 --- a/src/config_struct.rs +++ /dev/null @@ -1,50 +0,0 @@ -use serde::{Serialize, Deserialize}; - -/// Represents the main configuration for a machine. -/// -/// Fields: -/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. -/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. -/// - `dumpfile`: Optional string specifying the path to a dump file. -/// - `outfile`: Optional string specifying the path to an output file. -/// -/// Description: -/// - This struct is used to parse and hold the configuration data of a machine from various file formats. -/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. -/// -/// Purpose: -/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. -/// -/// Technical Explanation: -/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. -/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. -/// -#[derive(Serialize, Debug, Deserialize, Clone, Copy, Default)] -pub struct MachineConfig { - pub mmu_mode: Option, - pub memspaces: Vec, - pub dumpfile: Option, - pub outfile: Option, -} - -/// Defines a memory space with a type and address range. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] -pub struct MemorySpace { - pub space_type: SpaceType, - pub start_address: u64, - pub end_address: u64, -} - -/// Enumerates types of memory spaces. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] -pub enum SpaceType { - RAM, - ROM, -} - -/// Enumerates RISC-V MMU modes. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] -pub enum RiscVMMUMode { - SV39, - SV48, -} diff --git a/src/configuration.rs b/src/configuration.rs deleted file mode 100644 index fd42fc4..0000000 --- a/src/configuration.rs +++ /dev/null @@ -1,111 +0,0 @@ -mod config_struct; - -use std::fs; -use std::path::Path; -use std::env; -use anyhow::{Result, Context}; -use crate::config_struct::{MachineConfig, MemorySpace, SpaceType, RiscVMMUMode}; - -/// Loads configuration from a specified file. -/// -/// Args: -/// - `file_path`: The path to the configuration file. -/// -/// Returns: -/// - A `Result` containing `MachineConfig` or an error. -/// -/// Description: -/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. -/// -/// Purpose: -/// - To abstract the details of loading and parsing configuration files into a single reusable function. -/// -/// Technical Explanation: -/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. -/// - It handles TOML format. -/// -/// Example: -/// ```rust -/// let config = load_config("config.toml").unwrap(); -/// println!("{:?}", config); -/// ``` -pub fn load_config(file_path: &Path) -> Result { - let config_str = fs::read_to_string(file_path) - .with_context(|| format!("Failed to read configuration file: {:?}", file_path))?; - let mut config: MachineConfig = match file_path.extension().and_then(|s| s.to_str()) { - Some("toml") => toml::from_str(&config_str) - .with_context(|| format!("Failed to parse TOML configuration file: {:?}", file_path))?, - _ => return Err(anyhow::anyhow!("Unsupported file format: {:?}", file_path)), - }; - validate_config(&config)?; - Ok(config) -} -/// Validates the contents of the configuration. -/// -/// Args: -/// - `config`: The configuration to validate. -/// -/// Returns: -/// - A `Result` indicating whether the validation was successful. -pub fn validate_config(config: &MachineConfig) -> Result<()> { - if let Some(ref mode) = config.mmu_mode { - match mode.as_str() { - "SV39" | "SV48" => Ok(()), - _ => Err(anyhow::anyhow!("Invalid MMU mode: {}", mode)), - } - } else { - Ok(()) - } -} - -/// -///fn main() -> Result<()> { -/// //Collect command line arguments -/// let args: Vec = env::args().collect(); -/// // Check if a file path is provided -/// if args.len() < 2 { -/// eprintln!("Usage: {} ", args[0]); -/// std::process::exit(1); -/// } -/// // The file path is the second argument -/// let config_path = Path::new(&args[1]); -/// // Output the path for debugging purposes -/// println!("Loading configuration from: {:?}", config_path); -/// // Attempt to load the configuration -/// let file_conf = load_config(config_path)?; -/// // Output the loaded configuration for verification -/// println!("Loaded Configuration: {:#?}", file_conf); -/// -/// // Manually convert `mmu_mode` to `RiscVMMUMode` -/// let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { -/// Some("SV39") => Some(RiscVMMUMode::SV39), -/// Some("SV48") => Some(RiscVMMUMode::SV48), -/// _ => None, -/// }; -/// -/// // Inline configuration example -/// let inline_conf = MachineConfig { -/// mmu_mode: Some("SV39".to_string()), -/// memspaces: vec![ -/// MemorySpace { -/// space_type: SpaceType::RAM, -/// start_address: 0x0000000080000000, -/// end_address: 0x000000017fffffff, -/// }, -/// MemorySpace { -/// space_type: SpaceType::ROM, -/// start_address: 0x0000000000000000, -/// end_address: 0x0000000000011fff, -/// }, -/// ], -/// dumpfile: Some("dump.raw".to_string()), -/// outfile: Some("output.txt".to_string()), -/// }; -/// -/// // Output the loaded configuration and the manually converted MMU mode -/// println!("File-based Configuration: {:#?}", file_conf); -/// println!("MMU Mode: {:?}", mmu_mode); -/// println!("Inline Configuration: {:#?}", inline_conf); -/// Ok(()) -///} -/// \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index e69de29..2d148af 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -0,0 +1 @@ +pub mod configuration; diff --git a/src/utils/config_struct.rs b/src/utils/config_struct.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/utils/config_struct.rs @@ -0,0 +1 @@ + diff --git a/src/utils/configuration.rs b/src/utils/configuration.rs new file mode 100644 index 0000000..97aee46 --- /dev/null +++ b/src/utils/configuration.rs @@ -0,0 +1,159 @@ +use anyhow::{Context, Result}; +use std::fs; +use std::path::Path; + +use serde::{Deserialize, Serialize}; + +/// Represents the main configuration for a machine. +/// +/// Fields: +/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. +/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. +/// - `dumpfile`: Optional string specifying the path to a dump file. +/// - `outfile`: Optional string specifying the path to an output file. +/// +/// Description: +/// - This struct is used to parse and hold the configuration data of a machine from various file formats. +/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. +/// +/// Purpose: +/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. +/// +/// Technical Explanation: +/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. +/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. +/// +#[derive(Serialize, Debug, Deserialize, Clone, Default)] +pub struct MachineConfig { + pub mmu_mode: Option, + pub memspaces: Vec, + pub dumpfile: Option, + pub outfile: Option, +} + +/// Defines a memory space with a type and address range. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] +pub struct MemorySpace { + pub space_type: SpaceType, + pub start_address: u64, + pub end_address: u64, +} + +/// Enumerates types of memory spaces. +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub enum SpaceType { + RAM, + ROM, +} + +/// Enumerates RISC-V MMU modes. +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub enum RiscVMMUMode { + SV39, + SV48, +} + +/// Loads configuration from a specified file. +/// +/// Args: +/// - `file_path`: The path to the configuration file. +/// +/// Returns: +/// - A `Result` containing `MachineConfig` or an error. +/// +/// Description: +/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. +/// +/// Purpose: +/// - To abstract the details of loading and parsing configuration files into a single reusable function. +/// +/// Technical Explanation: +/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. +/// - It handles TOML format. +/// +/// Example: +/// ```rust +/// let config = load_config("config.toml").unwrap(); +/// println!("{:?}", config); +/// ``` +pub fn load_config(file_path: &Path) -> Result { + let config_str = fs::read_to_string(file_path) + .with_context(|| format!("Failed to read configuration file: {:?}", file_path))?; + let mut config: MachineConfig = match file_path.extension().and_then(|s| s.to_str()) { + Some("toml") => toml::from_str(&config_str) + .with_context(|| format!("Failed to parse TOML configuration file: {:?}", file_path))?, + _ => return Err(anyhow::anyhow!("Unsupported file format: {:?}", file_path)), + }; + validate_config(&config)?; + Ok(config) +} + +/// Validates the contents of the configuration. +/// +/// Args: +/// - `config`: The configuration to validate. +/// +/// Returns: +/// - A `Result` indicating whether the validation was successful. +pub fn validate_config(config: &MachineConfig) -> Result<()> { + if let Some(ref mode) = config.mmu_mode { + match mode.as_str() { + "SV39" | "SV48" => Ok(()), + _ => Err(anyhow::anyhow!("Invalid MMU mode: {}", mode)), + } + } else { + Ok(()) + } +} + +// +//fn main() -> Result<()> { +// //Collect command line arguments +// let args: Vec = env::args().collect(); +// // Check if a file path is provided +// if args.len() < 2 { +// eprintln!("Usage: {} ", args[0]); +// std::process::exit(1); +// } +// // The file path is the second argument +// let config_path = Path::new(&args[1]); +// // Output the path for debugging purposes +// println!("Loading configuration from: {:?}", config_path); +// // Attempt to load the configuration +// let file_conf = load_config(config_path)?; +// // Output the loaded configuration for verification +// println!("Loaded Configuration: {:#?}", file_conf); +// +// // Manually convert `mmu_mode` to `RiscVMMUMode` +// let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { +// Some("SV39") => Some(RiscVMMUMode::SV39), +// Some("SV48") => Some(RiscVMMUMode::SV48), +// _ => None, +// }; +// +// // Inline configuration example +// let inline_conf = MachineConfig { +// mmu_mode: Some("SV39".to_string()), +// memspaces: vec![ +// MemorySpace { +// space_type: SpaceType::RAM, +// start_address: 0x0000000080000000, +// end_address: 0x000000017fffffff, +// }, +// MemorySpace { +// space_type: SpaceType::ROM, +// start_address: 0x0000000000000000, +// end_address: 0x0000000000011fff, +// }, +// ], +// dumpfile: Some("dump.raw".to_string()), +// outfile: Some("output.txt".to_string()), +// }; +// +// // Output the loaded configuration and the manually converted MMU mode +// println!("File-based Configuration: {:#?}", file_conf); +// println!("MMU Mode: {:?}", mmu_mode); +// println!("Inline Configuration: {:#?}", inline_conf); +// Ok(()) +//} +// From 142b7dfc7d0822618775f89ba5bc756ba6e27d6e Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:08:20 +0200 Subject: [PATCH 24/46] del: useless struct --- src/utils/config_struct.rs | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/utils/config_struct.rs diff --git a/src/utils/config_struct.rs b/src/utils/config_struct.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/utils/config_struct.rs +++ /dev/null @@ -1 +0,0 @@ - From 0e61d34aeb2982ab5a7b595a58369cf5ff4ba8b1 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:30:22 +0200 Subject: [PATCH 25/46] fix: added &self to generic traits --- src/architecture/generic.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/architecture/generic.rs b/src/architecture/generic.rs index 65c5205..a35bd4c 100644 --- a/src/architecture/generic.rs +++ b/src/architecture/generic.rs @@ -39,7 +39,7 @@ pub struct MemoryRegion { pub trait CPURegister { type Value: hash::Hash + Eq + Copy + Default; - fn is_valid() -> Result; + fn is_valid(&self) -> Result; } /// Represents a page table entry with an address and flags. @@ -50,12 +50,12 @@ pub trait PageTableEntry { type Address: hash::Hash + Eq + Copy + Default; type Flags: hash::Hash + Eq + Copy + Default; - fn is_dirty() -> bool; - fn is_accessed() -> bool; - fn is_global() -> bool; - fn is_readable() -> bool; - fn is_writable() -> bool; - fn is_executable() -> bool; + fn is_dirty(&self) -> bool; + fn is_accessed(&self) -> bool; + fn is_global(&self) -> bool; + fn is_readable(&self) -> bool; + fn is_writable(&self) -> bool; + fn is_executable(&self) -> bool; } /// Represents a page table with entries. From a0550360da194c8968bbb8d139f75b6e304accd6 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:30:37 +0200 Subject: [PATCH 26/46] feat: riscv base structs --- src/architecture/riscv.rs | 85 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs index e69de29..c4cd209 100644 --- a/src/architecture/riscv.rs +++ b/src/architecture/riscv.rs @@ -0,0 +1,85 @@ +use super::generic::{CPURegister, PageTableEntry}; + +use anyhow::Result; +use serde::{Deserialize, Serialize}; + +/// Represents a RISC-V CPU register associated with a value. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, Hash, Eq, PartialEq)] +pub struct RiscVCPURegister { + pub value: u64, +} + +impl CPURegister for RiscVCPURegister { + type Value = u64; + + fn is_valid(&self) -> Result { + // FIXME: Implement validation logic + Ok(self.value) + } +} + +impl RiscVCPURegister { + pub fn new(value: u64) -> Self { + Self { value } + } +} + +/// Represents a RISC-V page table entry. +/// It holds the mapping between a virtual address of a page and the address of a physical frame. +/// There is also auxiliary information about the page such as a present bit, a dirty or modified bit, +/// address space or process ID information, amongst others. +#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq, PartialEq)] +pub struct RiscVPageTableEntry { + pub address: u64, + pub flags: u64, +} + +impl RiscVPageTableEntry { + pub fn new(address: u64, flags: u64) -> Self { + Self { address, flags } + } + + pub fn is_supervisor(&self) -> bool { + self.flags & 0x1 == 0 + } +} + +impl PageTableEntry for RiscVPageTableEntry { + type Address = u64; + type Flags = u64; + + // FIXME: Implement the following methods + fn is_dirty(&self) -> bool { + true + } + + fn is_accessed(&self) -> bool { + true + } + + fn is_global(&self) -> bool { + true + } + + fn is_readable(&self) -> bool { + true + } + + fn is_writable(&self) -> bool { + true + } + + fn is_executable(&self) -> bool { + true + } +} + +/// Enumerates RISC-V MMU modes. +/// The MMU modes are used to determine the number of bits used for virtual and physical addresses. +/// The modes are named after the number of bits used for the virtual address space. +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub enum RiscVMMUMode { + SV32, + SV39, + SV48, +} From bd3b9fd65deefc7d1b3eb53c2bfc7150f2e87710 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:58:23 +0200 Subject: [PATCH 27/46] feat: added machine struct --- src/architecture/generic.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/architecture/generic.rs b/src/architecture/generic.rs index a35bd4c..da3923d 100644 --- a/src/architecture/generic.rs +++ b/src/architecture/generic.rs @@ -1,6 +1,6 @@ use anyhow::Result; use serde::{Deserialize, Serialize}; -use std::hash; +use std::{hash, path::PathBuf}; // MemoryRegion // CPU @@ -67,3 +67,24 @@ pub trait PageTable { // fn apply_on_entries(function: FnMut(PageTableEntry) -> Vec ) -> ? // to be defined } + +pub trait CPU {} + +pub trait MMU {} + +/// Enumerates types of supported machines. +/// This enum is used to specify the type of machine that is being parsed. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MachineType { + RiscV, +} + +/// Represents a machine with a type, MMU, CPU, memory regions, and an associated dump file. +/// It is used to store the machine's configuration, memory regions, and the dump file that is being used. +pub struct Machine { + pub _type: MachineType, + pub mmu: Box, + pub cpu: Box, + pub memory_regions: Vec, + pub dumpfile: Option, +} From d53d989d9130f4510eeaea403e0c2ab208b0a015 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:58:37 +0200 Subject: [PATCH 28/46] chore: common traits on riscv mmumode --- src/architecture/riscv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs index c4cd209..5e62f5a 100644 --- a/src/architecture/riscv.rs +++ b/src/architecture/riscv.rs @@ -77,7 +77,7 @@ impl PageTableEntry for RiscVPageTableEntry { /// Enumerates RISC-V MMU modes. /// The MMU modes are used to determine the number of bits used for virtual and physical addresses. /// The modes are named after the number of bits used for the virtual address space. -#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq, PartialEq)] pub enum RiscVMMUMode { SV32, SV39, From 38433e9667b38be787f2e9da1a7ef90cf169361d Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:58:57 +0200 Subject: [PATCH 29/46] fmt: removed useless docstrings --- src/utils/configuration.rs | 133 ------------------------------------- 1 file changed, 133 deletions(-) diff --git a/src/utils/configuration.rs b/src/utils/configuration.rs index 97aee46..89d4ecd 100644 --- a/src/utils/configuration.rs +++ b/src/utils/configuration.rs @@ -2,80 +2,6 @@ use anyhow::{Context, Result}; use std::fs; use std::path::Path; -use serde::{Deserialize, Serialize}; - -/// Represents the main configuration for a machine. -/// -/// Fields: -/// - `mmu_mode`: Optional string that specifies the MMU mode, which will be manually converted to a specific type. -/// - `memspaces`: A vector of `MemorySpace` that defines different memory regions. -/// - `dumpfile`: Optional string specifying the path to a dump file. -/// - `outfile`: Optional string specifying the path to an output file. -/// -/// Description: -/// - This struct is used to parse and hold the configuration data of a machine from various file formats. -/// - It includes memory spaces, MMU mode, and optional paths for dump and output files. -/// -/// Purpose: -/// - To provide a structured representation of machine configuration that can be easily loaded, manipulated, and accessed. -/// -/// Technical Explanation: -/// - The `mmu_mode` is stored as a string to allow flexibility in how it is represented and used in different contexts. -/// - `memspaces` is a vector of `MemorySpace`, which details the type and address range of memory spaces. -/// -#[derive(Serialize, Debug, Deserialize, Clone, Default)] -pub struct MachineConfig { - pub mmu_mode: Option, - pub memspaces: Vec, - pub dumpfile: Option, - pub outfile: Option, -} - -/// Defines a memory space with a type and address range. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] -pub struct MemorySpace { - pub space_type: SpaceType, - pub start_address: u64, - pub end_address: u64, -} - -/// Enumerates types of memory spaces. -#[derive(Serialize, Deserialize, Debug, Clone, Copy)] -pub enum SpaceType { - RAM, - ROM, -} - -/// Enumerates RISC-V MMU modes. -#[derive(Serialize, Deserialize, Debug, Clone, Copy)] -pub enum RiscVMMUMode { - SV39, - SV48, -} - -/// Loads configuration from a specified file. -/// -/// Args: -/// - `file_path`: The path to the configuration file. -/// -/// Returns: -/// - A `Result` containing `MachineConfig` or an error. -/// -/// Description: -/// - This function reads a configuration file and deserializes it into a `MachineConfig` instance. -/// -/// Purpose: -/// - To abstract the details of loading and parsing configuration files into a single reusable function. -/// -/// Technical Explanation: -/// - The function determines the file format based on the extension and uses the appropriate Serde deserializer. -/// - It handles TOML format. -/// -/// Example: -/// ```rust -/// let config = load_config("config.toml").unwrap(); -/// println!("{:?}", config); -/// ``` pub fn load_config(file_path: &Path) -> Result { let config_str = fs::read_to_string(file_path) .with_context(|| format!("Failed to read configuration file: {:?}", file_path))?; @@ -88,13 +14,6 @@ pub fn load_config(file_path: &Path) -> Result { Ok(config) } -/// Validates the contents of the configuration. -/// -/// Args: -/// - `config`: The configuration to validate. -/// -/// Returns: -/// - A `Result` indicating whether the validation was successful. pub fn validate_config(config: &MachineConfig) -> Result<()> { if let Some(ref mode) = config.mmu_mode { match mode.as_str() { @@ -105,55 +24,3 @@ pub fn validate_config(config: &MachineConfig) -> Result<()> { Ok(()) } } - -// -//fn main() -> Result<()> { -// //Collect command line arguments -// let args: Vec = env::args().collect(); -// // Check if a file path is provided -// if args.len() < 2 { -// eprintln!("Usage: {} ", args[0]); -// std::process::exit(1); -// } -// // The file path is the second argument -// let config_path = Path::new(&args[1]); -// // Output the path for debugging purposes -// println!("Loading configuration from: {:?}", config_path); -// // Attempt to load the configuration -// let file_conf = load_config(config_path)?; -// // Output the loaded configuration for verification -// println!("Loaded Configuration: {:#?}", file_conf); -// -// // Manually convert `mmu_mode` to `RiscVMMUMode` -// let mmu_mode: Option = match file_conf.mmu_mode.as_deref() { -// Some("SV39") => Some(RiscVMMUMode::SV39), -// Some("SV48") => Some(RiscVMMUMode::SV48), -// _ => None, -// }; -// -// // Inline configuration example -// let inline_conf = MachineConfig { -// mmu_mode: Some("SV39".to_string()), -// memspaces: vec![ -// MemorySpace { -// space_type: SpaceType::RAM, -// start_address: 0x0000000080000000, -// end_address: 0x000000017fffffff, -// }, -// MemorySpace { -// space_type: SpaceType::ROM, -// start_address: 0x0000000000000000, -// end_address: 0x0000000000011fff, -// }, -// ], -// dumpfile: Some("dump.raw".to_string()), -// outfile: Some("output.txt".to_string()), -// }; -// -// // Output the loaded configuration and the manually converted MMU mode -// println!("File-based Configuration: {:#?}", file_conf); -// println!("MMU Mode: {:?}", mmu_mode); -// println!("Inline Configuration: {:#?}", inline_conf); -// Ok(()) -//} -// From d29f5b0e5a052b2c7000865dcd3d4666f3dbc7a0 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:53:28 +0200 Subject: [PATCH 30/46] del: useless tests files --- src/utils/configuration.rs | 26 -------------------------- tests/test.json | 17 ----------------- tests/test.xml | 17 ----------------- tests/test.yaml | 13 ------------- 4 files changed, 73 deletions(-) delete mode 100644 src/utils/configuration.rs delete mode 100644 tests/test.json delete mode 100644 tests/test.xml delete mode 100644 tests/test.yaml diff --git a/src/utils/configuration.rs b/src/utils/configuration.rs deleted file mode 100644 index 89d4ecd..0000000 --- a/src/utils/configuration.rs +++ /dev/null @@ -1,26 +0,0 @@ -use anyhow::{Context, Result}; -use std::fs; -use std::path::Path; - -pub fn load_config(file_path: &Path) -> Result { - let config_str = fs::read_to_string(file_path) - .with_context(|| format!("Failed to read configuration file: {:?}", file_path))?; - let mut config: MachineConfig = match file_path.extension().and_then(|s| s.to_str()) { - Some("toml") => toml::from_str(&config_str) - .with_context(|| format!("Failed to parse TOML configuration file: {:?}", file_path))?, - _ => return Err(anyhow::anyhow!("Unsupported file format: {:?}", file_path)), - }; - validate_config(&config)?; - Ok(config) -} - -pub fn validate_config(config: &MachineConfig) -> Result<()> { - if let Some(ref mode) = config.mmu_mode { - match mode.as_str() { - "SV39" | "SV48" => Ok(()), - _ => Err(anyhow::anyhow!("Invalid MMU mode: {}", mode)), - } - } else { - Ok(()) - } -} diff --git a/tests/test.json b/tests/test.json deleted file mode 100644 index 84431bf..0000000 --- a/tests/test.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "mmu_mode": "SV39", - "memspaces": [ - { - "space_type": "RAM", - "start_address": 34359738368, - "end_address": 103079215103 - }, - { - "space_type": "ROM", - "start_address": 0, - "end_address": 73727 - } - ], - "dumpfile": "example_dump.raw", - "outfile": "example_output.txt" -} diff --git a/tests/test.xml b/tests/test.xml deleted file mode 100644 index c5c2364..0000000 --- a/tests/test.xml +++ /dev/null @@ -1,17 +0,0 @@ - - SV39 - - - RAM - 34359738368 - 103079215103 - - - ROM - 0 - 73727 - - - example_dump.raw - example_output.txt - diff --git a/tests/test.yaml b/tests/test.yaml deleted file mode 100644 index a87f10b..0000000 --- a/tests/test.yaml +++ /dev/null @@ -1,13 +0,0 @@ -mmu_mode: "SV39" - -memspaces: - - space_type: "RAM" - start_address: 34359738368 - end_address: 103079215103 - - - space_type: "ROM" - start_address: 0 - end_address: 73727 - -dumpfile: "example_dump.raw" -outfile: "example_output.txt" From 7cd604d803a7a970ef9b71c96a5eda5b5abdbcbd Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:53:40 +0200 Subject: [PATCH 31/46] chore: easily identifiable addresses --- tests/test.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test.toml b/tests/test.toml index 86d9763..7f2e1df 100644 --- a/tests/test.toml +++ b/tests/test.toml @@ -2,8 +2,8 @@ mmu_mode = "SV39" [[memspaces]] space_type = "RAM" -start_address = 34359738368 -end_address = 103079215103 +start_address = 0x12345678 +end_address = 0x87654321 [[memspaces]] space_type = "ROM" From ad93938710040beb4d1b6c7000bf63b5e085574b Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:56:18 +0200 Subject: [PATCH 32/46] feat: MemoryRegion impl, added MemorySpace, Machine generic struct --- src/architecture/generic.rs | 103 +++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 7 deletions(-) diff --git a/src/architecture/generic.rs b/src/architecture/generic.rs index da3923d..fe58d37 100644 --- a/src/architecture/generic.rs +++ b/src/architecture/generic.rs @@ -14,7 +14,7 @@ use std::{hash, path::PathBuf}; // Machine /// Enumerates types of memory regions. -#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MemoryRegionType { RAM, ROM, @@ -27,13 +27,83 @@ impl Default for MemoryRegionType { } /// Represents a memory region with a start and end address. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] pub struct MemoryRegion { pub _type: MemoryRegionType, pub start_address: u64, pub end_address: u64, } +impl MemoryRegion { + pub fn new(_type: MemoryRegionType, start_address: u64, end_address: u64) -> Result { + // Check that addresses are valid memory addresses + if start_address >= end_address { + return Err(anyhow::anyhow!( + "Invalid memory region, start address is greater than or equal to end address" + )); + } + + if start_address >= u64::MAX || end_address >= u64::MAX { + return Err(anyhow::anyhow!( + "Invalid memory address, address is greater than u64::MAX" + )); + } + + Ok(Self { + _type, + start_address, + end_address, + }) + } + + /// Returns the size of the memory region. + pub fn size(&self) -> u64 { + self.end_address - self.start_address + } + + /// Returns true if the memory region contains the address. + /// A memory region contains an address if the address is greater than or equal to the start address and less than the end address. + pub fn contains(&self, address: u64) -> bool { + self.start_address <= address && address < self.end_address + } + + /// Returns true if the two memory regions are overlapping. + /// Two memory regions are overlapping if the start address of one region is less than the end address of the other region. + pub fn is_overlapping(&self, other: &MemoryRegion) -> bool { + self.contains(other.start_address) || other.contains(self.start_address) + } + + /// Returns true if the two memory regions are adjacent. + /// Two memory regions are adjacent if the end address of one region is equal to the start address of the other region. + pub fn is_adjacent(&self, other: &MemoryRegion) -> bool { + self.start_address == other.end_address || other.start_address == self.end_address + } +} + +/// Represents a memory space with regions. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct MemorySpace { + pub regions: Vec, +} + +impl MemorySpace { + pub fn new(regions: Vec) -> Self { + Self { regions } + } + + pub fn add(&mut self, region: MemoryRegion) -> Result<&mut Self> { + // Check if the memory region is overlapping with another region + if self.regions.iter().any(|r| r.is_overlapping(®ion)) { + return Err(anyhow::anyhow!( + "Memory region is overlapping with another region" + )); + } + + self.regions.push(region); + Ok(self) + } +} + /// Represents a CPU register with a value. /// Depending on the architecture, the *validity* changes. pub trait CPURegister { @@ -65,7 +135,7 @@ pub trait PageTableEntry { pub trait PageTable { type Entries: hash::Hash + Eq + Copy + Default + PageTableEntry; - // fn apply_on_entries(function: FnMut(PageTableEntry) -> Vec ) -> ? // to be defined + // fn apply_on_entries(function: FnMut(PageTableEntry) -> Vec ) -> ? // FIXME: to be defined, but is it necessary? } pub trait CPU {} @@ -81,10 +151,29 @@ pub enum MachineType { /// Represents a machine with a type, MMU, CPU, memory regions, and an associated dump file. /// It is used to store the machine's configuration, memory regions, and the dump file that is being used. -pub struct Machine { +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Machine { pub _type: MachineType, - pub mmu: Box, - pub cpu: Box, + pub mmu: T, + pub cpu: U, pub memory_regions: Vec, - pub dumpfile: Option, + pub dumpfile: PathBuf, +} + +impl Machine { + pub fn new( + _type: MachineType, + mmu: T, + cpu: U, + memory_regions: Vec, + dumpfile: PathBuf, + ) -> Self { + Self { + _type, + mmu, + cpu, + memory_regions, + dumpfile, + } + } } From 437fd3ba7128d1f428c9cedd34d69b4a0481485d Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:56:43 +0200 Subject: [PATCH 33/46] feat: created TryFromPath and FromPath traits --- src/utils.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/utils.rs b/src/utils.rs index 2d148af..27f8151 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1 +1,28 @@ -pub mod configuration; +use anyhow::Result; +use std::path::{Path, PathBuf}; + +/// Try to convert from a path. +pub trait TryFromPath { + /// Converts from a path reference. + fn from_path(path: &Path) -> Result + where + Self: Sized; +} + +/// Defines a trait for converting from a path. +pub trait FromPath { + /// Converts from a path reference. + fn from_path(path: &Path) -> Self; +} + +impl FromPath for String { + fn from_path(path: &Path) -> String { + path.to_string_lossy().into_owned() + } +} + +impl FromPath for PathBuf { + fn from_path(path: &Path) -> PathBuf { + path.to_path_buf() + } +} From b377b998648994e584b4e33e2457f43e667e37dd Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:57:20 +0200 Subject: [PATCH 34/46] wip: moved configuration to root --- src/configuration.rs | 19 +++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 20 insertions(+) create mode 100644 src/configuration.rs diff --git a/src/configuration.rs b/src/configuration.rs new file mode 100644 index 0000000..5d585da --- /dev/null +++ b/src/configuration.rs @@ -0,0 +1,19 @@ +use anyhow::Result; +use std::fs; +use std::path::Path; + +use crate::utils::TryFromPath; + +use super::architecture::generic::Machine; + +/// Represents a configuration file for a machine. +/// It holds information about the machine's architecture, memory regions, and other relevant information. +/// The configuration file must be written in the TOML format. +impl TryFromPath for Machine { + fn from_path(path: &Path) -> Result { + let configuration = fs::read_to_string(path)?; + let machine: Machine = toml::from_str(&configuration)?; + + Ok(machine) + } +} diff --git a/src/lib.rs b/src/lib.rs index 6e975b1..f295f55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod architecture; +pub mod configuration; pub mod utils; From 297e7726648860780db17d3c30e5aea510c93d8c Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:11:55 +0200 Subject: [PATCH 35/46] fix: implement from_path to every machine --- src/configuration.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/configuration.rs b/src/configuration.rs index 5d585da..c87f5d6 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,18 +1,23 @@ use anyhow::Result; +use serde::de::DeserializeOwned; use std::fs; use std::path::Path; use crate::utils::TryFromPath; -use super::architecture::generic::Machine; +use super::architecture::generic::{Machine, CPU, MMU}; /// Represents a configuration file for a machine. /// It holds information about the machine's architecture, memory regions, and other relevant information. /// The configuration file must be written in the TOML format. -impl TryFromPath for Machine { +impl TryFromPath for Machine +where + T: CPU + DeserializeOwned, + U: MMU + DeserializeOwned, +{ fn from_path(path: &Path) -> Result { let configuration = fs::read_to_string(path)?; - let machine: Machine = toml::from_str(&configuration)?; + let machine: Machine = toml::from_str(&configuration)?; Ok(machine) } From 037f9272e201a348b733ad64f74ec12c1a4dc306 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:15:34 +0200 Subject: [PATCH 36/46] =?UTF-8?q?fix:=20clippy=20=C3=A8=5F=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/architecture/generic.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/architecture/generic.rs b/src/architecture/generic.rs index fe58d37..02bf836 100644 --- a/src/architecture/generic.rs +++ b/src/architecture/generic.rs @@ -14,18 +14,13 @@ use std::{hash, path::PathBuf}; // Machine /// Enumerates types of memory regions. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum MemoryRegionType { + #[default] RAM, ROM, } -impl Default for MemoryRegionType { - fn default() -> Self { - MemoryRegionType::RAM - } -} - /// Represents a memory region with a start and end address. #[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] pub struct MemoryRegion { @@ -43,12 +38,6 @@ impl MemoryRegion { )); } - if start_address >= u64::MAX || end_address >= u64::MAX { - return Err(anyhow::anyhow!( - "Invalid memory address, address is greater than u64::MAX" - )); - } - Ok(Self { _type, start_address, From 0ae4e35cf154fa1b23da676453b4af511c565431 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:15:45 +0200 Subject: [PATCH 37/46] fix: removed false assertion --- src/architecture/riscv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs index 5e62f5a..a92ee8a 100644 --- a/src/architecture/riscv.rs +++ b/src/architecture/riscv.rs @@ -40,7 +40,7 @@ impl RiscVPageTableEntry { } pub fn is_supervisor(&self) -> bool { - self.flags & 0x1 == 0 + true // FIXME: Implement validation logic } } From aa5299d2baec48e392de2c76982713cacd2ec522 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:46:22 +0200 Subject: [PATCH 38/46] feat: renamed test to riscv sample --- tests/config/test.toml | 14 -------------- tests/fixtures/riscv-sample.toml | 14 ++++++++++++++ tests/test.toml | 14 -------------- 3 files changed, 14 insertions(+), 28 deletions(-) delete mode 100644 tests/config/test.toml create mode 100644 tests/fixtures/riscv-sample.toml delete mode 100644 tests/test.toml diff --git a/tests/config/test.toml b/tests/config/test.toml deleted file mode 100644 index 86d9763..0000000 --- a/tests/config/test.toml +++ /dev/null @@ -1,14 +0,0 @@ -mmu_mode = "SV39" - -[[memspaces]] -space_type = "RAM" -start_address = 34359738368 -end_address = 103079215103 - -[[memspaces]] -space_type = "ROM" -start_address = 0 -end_address = 73727 - -dumpfile = "example_dump.raw" -outfile = "example_output.txt" diff --git a/tests/fixtures/riscv-sample.toml b/tests/fixtures/riscv-sample.toml new file mode 100644 index 0000000..80a59fc --- /dev/null +++ b/tests/fixtures/riscv-sample.toml @@ -0,0 +1,14 @@ +mmu_mode = "SV39" + +[[memspaces]] +space_type = "RAM" # test RAM +start_address = 0x12345678 # test hex numbers +end_address = 0x87654321 + +[[memspaces]] +space_type = "ROM" # test ROM +start_address = 0 +end_address = 73727 # test decimal numbers + + +dumpfile = "riscv-sv39.raw" diff --git a/tests/test.toml b/tests/test.toml deleted file mode 100644 index 7f2e1df..0000000 --- a/tests/test.toml +++ /dev/null @@ -1,14 +0,0 @@ -mmu_mode = "SV39" - -[[memspaces]] -space_type = "RAM" -start_address = 0x12345678 -end_address = 0x87654321 - -[[memspaces]] -space_type = "ROM" -start_address = 0 -end_address = 73727 - -dumpfile = "example_dump.raw" -outfile = "example_output.txt" From a2962e8664fa0552eb0d933edb89c21fca51e932 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:46:37 +0200 Subject: [PATCH 39/46] del: useless file --- tests/test.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/test.rs diff --git a/tests/test.rs b/tests/test.rs deleted file mode 100644 index e69de29..0000000 From 372ff63e179a16a84178b97947c52aa406205f9d Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:46:52 +0200 Subject: [PATCH 40/46] feat: configuration integration test --- tests/configuration.rs | 55 ++++++++++++++++++++++++++++++++++++++++++ tests/integration.rs | 1 + 2 files changed, 56 insertions(+) create mode 100644 tests/configuration.rs create mode 100644 tests/integration.rs diff --git a/tests/configuration.rs b/tests/configuration.rs new file mode 100644 index 0000000..48d3497 --- /dev/null +++ b/tests/configuration.rs @@ -0,0 +1,55 @@ +#[cfg(test)] +mod configuration_tests { + use anyhow::Result; + use libmmu::architecture::generic::{ + Machine, MachineType, MemoryRegion, MemoryRegionType, MemorySpace, + }; + use libmmu::architecture::riscv::{RiscVCPU, RiscVMMU, RiscVMMUMode}; + use libmmu::utils::TryFromPath; + use std::path::{Path, PathBuf}; + + #[test] + fn create_riscv_configuration_from_code() -> Result<()> { + let machine_type = MachineType::RiscV; + let mmu = RiscVMMU::new(RiscVMMUMode::SV32); + let cpu = RiscVCPU::new(); + let dumpfile = PathBuf::from("tests/fixtures/riscv-sv32.dump"); + + let memspaces = MemorySpace::new() + .add(MemoryRegion { + _type: MemoryRegionType::RAM, + start_address: 0, + end_address: 1, + })? + .add(MemoryRegion { + _type: MemoryRegionType::ROM, + start_address: 2, + end_address: 3, + })? + .to_owned(); + + let machine = + Machine::::new(machine_type, cpu, mmu, memspaces, dumpfile); + + assert_eq!(machine._type, MachineType::RiscV); + assert_eq!(machine.cpu.registers.len(), 0); + assert_eq!(machine.mmu.mode, RiscVMMUMode::SV32); + assert_eq!(machine.memory_regions.regions.len(), 2); + assert_eq!( + machine.dumpfile, + PathBuf::from("tests/fixtures/riscv-sv32.dump") + ); + + Ok(()) + } + + // #[test] + // fn create_riscv_configuration_from_toml() { + // let path = Path::new("tests/fixtures/riscv.toml"); + // let machine = Machine::::from_path(path); + + // println!("{:?}", machine); + + // assert!(machine.is_ok()); + // } +} diff --git a/tests/integration.rs b/tests/integration.rs new file mode 100644 index 0000000..987f47d --- /dev/null +++ b/tests/integration.rs @@ -0,0 +1 @@ +mod configuration; From 8e7ab58a3e6cd2289f22cb54c42e98eff6322c39 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:47:36 +0200 Subject: [PATCH 41/46] fix: moved machine generic in the good order --- src/architecture/generic.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/architecture/generic.rs b/src/architecture/generic.rs index 02bf836..1e84c04 100644 --- a/src/architecture/generic.rs +++ b/src/architecture/generic.rs @@ -70,14 +70,16 @@ impl MemoryRegion { } /// Represents a memory space with regions. -#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Hash)] pub struct MemorySpace { pub regions: Vec, } impl MemorySpace { - pub fn new(regions: Vec) -> Self { - Self { regions } + pub fn new() -> Self { + Self { + regions: Vec::new(), + } } pub fn add(&mut self, region: MemoryRegion) -> Result<&mut Self> { @@ -143,24 +145,24 @@ pub enum MachineType { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] pub struct Machine { pub _type: MachineType, - pub mmu: T, - pub cpu: U, - pub memory_regions: Vec, + pub cpu: T, + pub mmu: U, + pub memory_regions: MemorySpace, pub dumpfile: PathBuf, } impl Machine { pub fn new( _type: MachineType, - mmu: T, - cpu: U, - memory_regions: Vec, + cpu: T, + mmu: U, + memory_regions: MemorySpace, dumpfile: PathBuf, ) -> Self { Self { _type, - mmu, cpu, + mmu, memory_regions, dumpfile, } From 3191018649b65db8d53715f1049389084fc8327d Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:47:55 +0200 Subject: [PATCH 42/46] feat: riscv cpu & mmu --- src/architecture/riscv.rs | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs index a92ee8a..ae0ba39 100644 --- a/src/architecture/riscv.rs +++ b/src/architecture/riscv.rs @@ -1,4 +1,4 @@ -use super::generic::{CPURegister, PageTableEntry}; +use super::generic::{CPURegister, PageTableEntry, CPU, MMU}; use anyhow::Result; use serde::{Deserialize, Serialize}; @@ -77,9 +77,40 @@ impl PageTableEntry for RiscVPageTableEntry { /// Enumerates RISC-V MMU modes. /// The MMU modes are used to determine the number of bits used for virtual and physical addresses. /// The modes are named after the number of bits used for the virtual address space. -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq, PartialEq)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq, PartialEq, Default)] pub enum RiscVMMUMode { + #[default] SV32, SV39, SV48, } + +/// Represents a RISC-V CPU. +#[derive(Debug, Clone, Serialize, Deserialize, Default, Hash, Eq, PartialEq)] +pub struct RiscVCPU { + pub registers: Vec, +} + +impl RiscVCPU { + pub fn new() -> Self { + Self { + registers: Vec::new(), + } + } +} + +impl CPU for RiscVCPU {} + +/// Represents a RISC-V MMU. +#[derive(Debug, Clone, Serialize, Deserialize, Default, Hash, Eq, PartialEq)] +pub struct RiscVMMU { + pub mode: RiscVMMUMode, +} + +impl RiscVMMU { + pub fn new(mode: RiscVMMUMode) -> Self { + Self { mode } + } +} + +impl MMU for RiscVMMU {} From 190acdec435b5cf615c5c3ea93b74094d7117551 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:28:24 +0200 Subject: [PATCH 43/46] feat: changed public machine API, removed useless traits, added integration tests --- README.md | 19 +++++--- src/architecture/generic.rs | 64 +++++++++++++-------------- src/architecture/riscv.rs | 34 +++++++-------- src/configuration.rs | 11 ++--- tests/configuration.rs | 74 +++++++++++++++++++++++--------- tests/fixtures/riscv-sample.toml | 19 ++++---- 6 files changed, 126 insertions(+), 95 deletions(-) diff --git a/README.md b/README.md index ceb722a..a6d4a61 100644 --- a/README.md +++ b/README.md @@ -46,21 +46,26 @@ todo - Add support for Binary Code Analysis with `miasm` ```rust +use anyhow::Result; use libmmu::architectures::{ RiscV, RiscVMMUMode }; use libmmu::utils::{ MemorySpace, SpaceType, MachineConfig }; -fn main() { +fn main() -> Result<()> { + let dumpfile = ...; + let outfolder = ...; + let memspaces = MemorySpace::new() .add(SpaceType::RAM, 0x0000000080000000, 0x000000017fffffff) .add(SpaceType::ROM, 0x0000000000000000, 0x0000000000011fff); - let conf = MachineConfig::::new() - .dumpfile("dump.raw") - .mmu(RiscVMMUMode::SV39) - .memspaces(memspaces) - .outfile("output"); + let machine = Machine::new( + MachineType::RiscV(MMUMode:SV32), + memspaces, + dumpfile, + outfolder + )?; - conf.resolve_spaces() + conf.resolve_spaces()?; } ``` diff --git a/src/architecture/generic.rs b/src/architecture/generic.rs index 1e84c04..0f68247 100644 --- a/src/architecture/generic.rs +++ b/src/architecture/generic.rs @@ -2,16 +2,7 @@ use anyhow::Result; use serde::{Deserialize, Serialize}; use std::{hash, path::PathBuf}; -// MemoryRegion -// CPU -// CPURegister -// PageTableEntry -// PageTable -// RadixTree -// VirtualAddressSpace -// PhysicalAddressSpace -// MMU -// Machine +use super::riscv::MMUMode as RiscVMMUMode; /// Enumerates types of memory regions. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] @@ -22,15 +13,19 @@ pub enum MemoryRegionType { } /// Represents a memory region with a start and end address. -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub struct MemoryRegion { - pub _type: MemoryRegionType, + pub region_type: MemoryRegionType, pub start_address: u64, pub end_address: u64, } impl MemoryRegion { - pub fn new(_type: MemoryRegionType, start_address: u64, end_address: u64) -> Result { + pub fn new( + region_type: MemoryRegionType, + start_address: u64, + end_address: u64, + ) -> Result { // Check that addresses are valid memory addresses if start_address >= end_address { return Err(anyhow::anyhow!( @@ -39,7 +34,7 @@ impl MemoryRegion { } Ok(Self { - _type, + region_type, start_address, end_address, }) @@ -70,7 +65,7 @@ impl MemoryRegion { } /// Represents a memory space with regions. -#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct MemorySpace { pub regions: Vec, } @@ -129,42 +124,47 @@ pub trait PageTable { // fn apply_on_entries(function: FnMut(PageTableEntry) -> Vec ) -> ? // FIXME: to be defined, but is it necessary? } -pub trait CPU {} - -pub trait MMU {} - /// Enumerates types of supported machines. /// This enum is used to specify the type of machine that is being parsed. #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MachineType { - RiscV, + RiscV(RiscVMMUMode), +} + +impl Default for MachineType { + fn default() -> Self { + Self::RiscV(RiscVMMUMode::SV32) + } } /// Represents a machine with a type, MMU, CPU, memory regions, and an associated dump file. /// It is used to store the machine's configuration, memory regions, and the dump file that is being used. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] -pub struct Machine { - pub _type: MachineType, - pub cpu: T, - pub mmu: U, +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Default)] +pub struct Machine { + /// Type of the machine and its associated MMU mode. + pub machine_type: MachineType, + /// Memory regions of the machine. pub memory_regions: MemorySpace, + /// Path to the dump file. pub dumpfile: PathBuf, + /// Path to the output folder. + pub outfolder: PathBuf, } -impl Machine { +impl Machine { pub fn new( - _type: MachineType, - cpu: T, - mmu: U, + machine_type: MachineType, memory_regions: MemorySpace, dumpfile: PathBuf, + outfolder: PathBuf, ) -> Self { + // TODO: Validate each field + Self { - _type, - cpu, - mmu, + machine_type, memory_regions, dumpfile, + outfolder, } } } diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs index ae0ba39..6d8d403 100644 --- a/src/architecture/riscv.rs +++ b/src/architecture/riscv.rs @@ -1,15 +1,15 @@ -use super::generic::{CPURegister, PageTableEntry, CPU, MMU}; +use super::generic::{CPURegister as CPURegisterTrait, PageTableEntry as PageTableEntryTrait}; use anyhow::Result; use serde::{Deserialize, Serialize}; /// Represents a RISC-V CPU register associated with a value. #[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, Hash, Eq, PartialEq)] -pub struct RiscVCPURegister { +pub struct CPURegister { pub value: u64, } -impl CPURegister for RiscVCPURegister { +impl CPURegisterTrait for CPURegister { type Value = u64; fn is_valid(&self) -> Result { @@ -18,7 +18,7 @@ impl CPURegister for RiscVCPURegister { } } -impl RiscVCPURegister { +impl CPURegister { pub fn new(value: u64) -> Self { Self { value } } @@ -29,12 +29,12 @@ impl RiscVCPURegister { /// There is also auxiliary information about the page such as a present bit, a dirty or modified bit, /// address space or process ID information, amongst others. #[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq, PartialEq)] -pub struct RiscVPageTableEntry { +pub struct PageTableEntry { pub address: u64, pub flags: u64, } -impl RiscVPageTableEntry { +impl PageTableEntry { pub fn new(address: u64, flags: u64) -> Self { Self { address, flags } } @@ -44,7 +44,7 @@ impl RiscVPageTableEntry { } } -impl PageTableEntry for RiscVPageTableEntry { +impl PageTableEntryTrait for PageTableEntry { type Address = u64; type Flags = u64; @@ -78,7 +78,7 @@ impl PageTableEntry for RiscVPageTableEntry { /// The MMU modes are used to determine the number of bits used for virtual and physical addresses. /// The modes are named after the number of bits used for the virtual address space. #[derive(Debug, Clone, Copy, Serialize, Deserialize, Hash, Eq, PartialEq, Default)] -pub enum RiscVMMUMode { +pub enum MMUMode { #[default] SV32, SV39, @@ -87,11 +87,11 @@ pub enum RiscVMMUMode { /// Represents a RISC-V CPU. #[derive(Debug, Clone, Serialize, Deserialize, Default, Hash, Eq, PartialEq)] -pub struct RiscVCPU { - pub registers: Vec, +pub struct CPU { + pub registers: Vec, } -impl RiscVCPU { +impl CPU { pub fn new() -> Self { Self { registers: Vec::new(), @@ -99,18 +99,14 @@ impl RiscVCPU { } } -impl CPU for RiscVCPU {} - /// Represents a RISC-V MMU. #[derive(Debug, Clone, Serialize, Deserialize, Default, Hash, Eq, PartialEq)] -pub struct RiscVMMU { - pub mode: RiscVMMUMode, +pub struct MMU { + pub mode: MMUMode, } -impl RiscVMMU { - pub fn new(mode: RiscVMMUMode) -> Self { +impl MMU { + pub fn new(mode: MMUMode) -> Self { Self { mode } } } - -impl MMU for RiscVMMU {} diff --git a/src/configuration.rs b/src/configuration.rs index c87f5d6..5d585da 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,23 +1,18 @@ use anyhow::Result; -use serde::de::DeserializeOwned; use std::fs; use std::path::Path; use crate::utils::TryFromPath; -use super::architecture::generic::{Machine, CPU, MMU}; +use super::architecture::generic::Machine; /// Represents a configuration file for a machine. /// It holds information about the machine's architecture, memory regions, and other relevant information. /// The configuration file must be written in the TOML format. -impl TryFromPath for Machine -where - T: CPU + DeserializeOwned, - U: MMU + DeserializeOwned, -{ +impl TryFromPath for Machine { fn from_path(path: &Path) -> Result { let configuration = fs::read_to_string(path)?; - let machine: Machine = toml::from_str(&configuration)?; + let machine: Machine = toml::from_str(&configuration)?; Ok(machine) } diff --git a/tests/configuration.rs b/tests/configuration.rs index 48d3497..61bbf7d 100644 --- a/tests/configuration.rs +++ b/tests/configuration.rs @@ -1,55 +1,89 @@ #[cfg(test)] mod configuration_tests { + use std::path::PathBuf; + use anyhow::Result; + use libmmu::architecture::generic::{ Machine, MachineType, MemoryRegion, MemoryRegionType, MemorySpace, }; - use libmmu::architecture::riscv::{RiscVCPU, RiscVMMU, RiscVMMUMode}; + use libmmu::architecture::riscv::MMUMode; use libmmu::utils::TryFromPath; - use std::path::{Path, PathBuf}; #[test] - fn create_riscv_configuration_from_code() -> Result<()> { - let machine_type = MachineType::RiscV; - let mmu = RiscVMMU::new(RiscVMMUMode::SV32); - let cpu = RiscVCPU::new(); + fn create_riscv_sv32_configuration_from_code() -> Result<()> { + let machine_type = MachineType::RiscV(MMUMode::SV32); let dumpfile = PathBuf::from("tests/fixtures/riscv-sv32.dump"); + let outfolder = PathBuf::from("tests/output"); let memspaces = MemorySpace::new() .add(MemoryRegion { - _type: MemoryRegionType::RAM, + region_type: MemoryRegionType::RAM, start_address: 0, end_address: 1, })? .add(MemoryRegion { - _type: MemoryRegionType::ROM, + region_type: MemoryRegionType::ROM, start_address: 2, end_address: 3, })? .to_owned(); - let machine = - Machine::::new(machine_type, cpu, mmu, memspaces, dumpfile); + let machine = Machine { + machine_type: machine_type, + memory_regions: memspaces, + dumpfile, + outfolder, + }; - assert_eq!(machine._type, MachineType::RiscV); - assert_eq!(machine.cpu.registers.len(), 0); - assert_eq!(machine.mmu.mode, RiscVMMUMode::SV32); + assert_eq!(machine.machine_type, MachineType::RiscV(MMUMode::SV32)); assert_eq!(machine.memory_regions.regions.len(), 2); + assert_eq!( + machine.memory_regions.regions[0].region_type, + MemoryRegionType::RAM + ); + assert_eq!(machine.memory_regions.regions[0].start_address, 0x12345678); + assert_eq!(machine.memory_regions.regions[0].end_address, 0x87654321); + assert_eq!( + machine.memory_regions.regions[1].region_type, + MemoryRegionType::ROM + ); + assert_eq!(machine.memory_regions.regions[1].start_address, 0); + assert_eq!(machine.memory_regions.regions[1].end_address, 73727); assert_eq!( machine.dumpfile, PathBuf::from("tests/fixtures/riscv-sv32.dump") ); + assert_eq!(machine.outfolder, PathBuf::from("tests/output")); Ok(()) } - // #[test] - // fn create_riscv_configuration_from_toml() { - // let path = Path::new("tests/fixtures/riscv.toml"); - // let machine = Machine::::from_path(path); + #[test] + fn create_riscv_sv32_configuration_from_toml() -> Result<()> { + let path = PathBuf::from("tests/fixtures/riscv-sample.toml"); + let machine = Machine::from_path(path.as_path())?; - // println!("{:?}", machine); + assert_eq!(machine.machine_type, MachineType::RiscV(MMUMode::SV32)); + assert_eq!(machine.memory_regions.regions.len(), 2); + assert_eq!( + machine.memory_regions.regions[0].region_type, + MemoryRegionType::RAM + ); + assert_eq!(machine.memory_regions.regions[0].start_address, 0x12345678); + assert_eq!(machine.memory_regions.regions[0].end_address, 0x87654321); + assert_eq!( + machine.memory_regions.regions[1].region_type, + MemoryRegionType::ROM + ); + assert_eq!(machine.memory_regions.regions[1].start_address, 0); + assert_eq!(machine.memory_regions.regions[1].end_address, 73727); + assert_eq!( + machine.dumpfile, + PathBuf::from("tests/fixtures/riscv-sv32.dump") + ); + assert_eq!(machine.outfolder, PathBuf::from("tests/output")); - // assert!(machine.is_ok()); - // } + Ok(()) + } } diff --git a/tests/fixtures/riscv-sample.toml b/tests/fixtures/riscv-sample.toml index 80a59fc..cce4a43 100644 --- a/tests/fixtures/riscv-sample.toml +++ b/tests/fixtures/riscv-sample.toml @@ -1,14 +1,15 @@ -mmu_mode = "SV39" +dumpfile = "tests/fixtures/riscv-sv32.dump" +outfolder = "tests/output" -[[memspaces]] -space_type = "RAM" # test RAM +[machine_type] +RiscV = "SV32" + +[[memory_regions.regions]] +region_type = "RAM" # test RAM start_address = 0x12345678 # test hex numbers end_address = 0x87654321 -[[memspaces]] -space_type = "ROM" # test ROM +[[memory_regions.regions]] +region_type = "ROM" start_address = 0 -end_address = 73727 # test decimal numbers - - -dumpfile = "riscv-sv39.raw" +end_address = 73727 From f67ed6ab7d7b574af8b5c0e01b26caec70ddb98a Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:30:58 +0200 Subject: [PATCH 44/46] fix: bad memory regions --- tests/configuration.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/configuration.rs b/tests/configuration.rs index 61bbf7d..af583b1 100644 --- a/tests/configuration.rs +++ b/tests/configuration.rs @@ -42,14 +42,14 @@ mod configuration_tests { machine.memory_regions.regions[0].region_type, MemoryRegionType::RAM ); - assert_eq!(machine.memory_regions.regions[0].start_address, 0x12345678); - assert_eq!(machine.memory_regions.regions[0].end_address, 0x87654321); + assert_eq!(machine.memory_regions.regions[0].start_address, 0); + assert_eq!(machine.memory_regions.regions[0].end_address, 1); assert_eq!( machine.memory_regions.regions[1].region_type, MemoryRegionType::ROM ); - assert_eq!(machine.memory_regions.regions[1].start_address, 0); - assert_eq!(machine.memory_regions.regions[1].end_address, 73727); + assert_eq!(machine.memory_regions.regions[1].start_address, 2); + assert_eq!(machine.memory_regions.regions[1].end_address, 3); assert_eq!( machine.dumpfile, PathBuf::from("tests/fixtures/riscv-sv32.dump") From 4bbd76b7d3966b6a4f17c2efe90369dbc5df5550 Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:38:28 +0200 Subject: [PATCH 45/46] fix: typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6d4a61..de9ed10 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ fn main() -> Result<()> { outfolder )?; - conf.resolve_spaces()?; + machine.resolve_spaces()?; } ``` From 4113a76f29b2c3c0c70de82d7995b58288a8725a Mon Sep 17 00:00:00 2001 From: std3 <67806187+standard3@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:56:22 +0200 Subject: [PATCH 46/46] fmt: changed fake data by todo! macros --- src/architecture/riscv.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs index 6d8d403..43d0543 100644 --- a/src/architecture/riscv.rs +++ b/src/architecture/riscv.rs @@ -13,8 +13,7 @@ impl CPURegisterTrait for CPURegister { type Value = u64; fn is_valid(&self) -> Result { - // FIXME: Implement validation logic - Ok(self.value) + todo!() } } @@ -40,7 +39,7 @@ impl PageTableEntry { } pub fn is_supervisor(&self) -> bool { - true // FIXME: Implement validation logic + todo!() } } @@ -50,27 +49,27 @@ impl PageTableEntryTrait for PageTableEntry { // FIXME: Implement the following methods fn is_dirty(&self) -> bool { - true + todo!() } fn is_accessed(&self) -> bool { - true + todo!() } fn is_global(&self) -> bool { - true + todo!() } fn is_readable(&self) -> bool { - true + todo!() } fn is_writable(&self) -> bool { - true + todo!() } fn is_executable(&self) -> bool { - true + todo!() } }