mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-04-21 19:24:00 +00:00
实现用户态程序
This commit is contained in:
49
shell/Commands/ExportTestExeCommand.cs
Normal file
49
shell/Commands/ExportTestExeCommand.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS)
|
||||
// Copyright (C) 2025-present LeonOS 2 Developer Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using IL2CPU.API.Attribs;
|
||||
|
||||
namespace CMLeonOS.Commands
|
||||
{
|
||||
public static class ExportTestExeCommand
|
||||
{
|
||||
[ManifestResourceStream(ResourceName = "CMLeonOS.sh.exe")]
|
||||
private static byte[] testExeBytes;
|
||||
|
||||
public static void ExportTestExe(string outputPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (testExeBytes == null || testExeBytes.Length == 0)
|
||||
{
|
||||
Console.WriteLine("Error: No test.exe found in embedded resources.");
|
||||
return;
|
||||
}
|
||||
|
||||
string destinationPath = string.IsNullOrEmpty(outputPath) ? @"0:\test.exe" : outputPath;
|
||||
|
||||
File.WriteAllBytes(destinationPath, testExeBytes);
|
||||
Console.WriteLine($"Test.exe exported successfully to: {destinationPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error exporting test.exe: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,18 @@ namespace CMLeonOS.Commands
|
||||
Description = "Simple calculator"
|
||||
},
|
||||
new CommandInfo
|
||||
{
|
||||
Command = "exporttestexe",
|
||||
Parameters = "<output>",
|
||||
Description = "Export test.exe to specified path"
|
||||
},
|
||||
new CommandInfo
|
||||
{
|
||||
Command = "exportbackground",
|
||||
Parameters = "<output>",
|
||||
Description = "Export background to specified path"
|
||||
},
|
||||
new CommandInfo
|
||||
{
|
||||
Command = "calcgui",
|
||||
Parameters = "",
|
||||
|
||||
105
shell/Commands/Script/RunbinCommand.cs
Normal file
105
shell/Commands/Script/RunbinCommand.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using Cosmos.System.Emulation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace CMLeonOS.Commands.Script
|
||||
{
|
||||
public static class RunbinCommand
|
||||
{
|
||||
public static void Execute(string args, CMLeonOS.FileSystem fileSystem, Action<string> showError)
|
||||
{
|
||||
string[] parts = args.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length < 1)
|
||||
{
|
||||
var commandInfos = new List<UsageGenerator.CommandInfo>
|
||||
{
|
||||
new UsageGenerator.CommandInfo
|
||||
{
|
||||
Command = "<file>",
|
||||
Description = "Run a MSE executable binary file",
|
||||
IsOptional = false
|
||||
}
|
||||
};
|
||||
showError(UsageGenerator.GenerateUsage("runbin", commandInfos));
|
||||
return;
|
||||
}
|
||||
|
||||
string inputPath = parts[0];
|
||||
string fullPath = fileSystem.GetFullPath(inputPath);
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
showError($"Error: File not found: {fullPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] data = File.ReadAllBytes(fullPath);
|
||||
if (data == null || data.Length == 0)
|
||||
{
|
||||
showError("Error: Executable file is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
FGMSECInstructionSet set = new FGMSECInstructionSet();
|
||||
Executable exec = new Executable(data, set, 3);
|
||||
|
||||
AddDefaultSystemCalls(exec);
|
||||
exec.ReadData();
|
||||
|
||||
while (exec.running)
|
||||
{
|
||||
exec.NextInstruction();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
showError($"runbin error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddDefaultSystemCalls(Executable exec)
|
||||
{
|
||||
// syscall 0: print null-terminated string at address in R3
|
||||
exec.AddSystemCall((Executable caller) =>
|
||||
{
|
||||
int addr = (int)((FGMSECInstructionSet)caller.usingInstructionSet).CPU.GetRegData(3);
|
||||
char c = (char)caller.Memory.ReadChar(addr);
|
||||
while (c != 0)
|
||||
{
|
||||
Console.Write(c);
|
||||
addr++;
|
||||
c = (char)caller.Memory.ReadChar(addr);
|
||||
}
|
||||
});
|
||||
|
||||
// syscall 1: read line and return address in R3
|
||||
exec.AddSystemCall((Executable caller) =>
|
||||
{
|
||||
string input = Console.ReadLine() ?? string.Empty;
|
||||
input += '\0';
|
||||
int addr = caller.Memory.Data.Count;
|
||||
int caddr = 0;
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
char c = input[i];
|
||||
if (!caller.Memory.AddChar(c))
|
||||
{
|
||||
caller.Memory.WriteChar(caddr, c);
|
||||
addr = 0;
|
||||
caddr++;
|
||||
}
|
||||
}
|
||||
((FGMSECInstructionSet)caller.usingInstructionSet).CPU.SetRegData(3, (uint)addr);
|
||||
});
|
||||
|
||||
// syscall 2: clear console
|
||||
exec.AddSystemCall((Executable caller) =>
|
||||
{
|
||||
Console.Clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user