实现用户态程序

This commit is contained in:
2026-03-27 21:32:18 +08:00
parent 7a7d44e9d8
commit 0988f4c820
13 changed files with 293 additions and 5 deletions

View 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}");
}
}
}
}

View File

@@ -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 = "",

View 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();
});
}
}
}