8#include "pedigree/kernel/Atomic.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/errors.h"
11#include "pedigree/kernel/process/Process.h"
12#include "pedigree/kernel/process/Thread.h"
13#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
14#include "pedigree/kernel/processor/Processor.h"
15#include "pedigree/kernel/utilities/utility.h"
21#include "modules/subsys/posix/FileDescriptor.h"
22#include "modules/subsys/posix/PosixSubsystem.h"
23#include "modules/subsys/posix/file-syscalls.h"
24#include "modules/system/console/Console.h"
29constexpr size_t TerminalDescriptor = 96;
30constexpr size_t LinuxTermiosExtent = 36;
31constexpr size_t LinuxControlCount = 19;
34struct MuslAmd64Termios {
55static_assert(
sizeof(MuslAmd64Termios) == 60,
"musl amd64 termios extent");
56static_assert(offsetof(MuslAmd64Termios, c_cc) == 17,
"musl amd64 control characters");
58struct TermiosContext {
68int termiosWorker(
void* parameter) {
69 TermiosContext* context =
reinterpret_cast<TermiosContext*
>(parameter);
73 const size_t reservedLength = pageSize * 2;
74 uintptr_t address = 0;
75 if (!context->process->allocateUserRange(Process::UserRegion::Normal, reservedLength, address)) {
78 uintptr_t mappedAddress = address;
80 mappedAddress, pageSize, MemoryMappedObject::Read | MemoryMappedObject::Write);
81 if (!mapping || mappedAddress != address) {
83 context->process->freeUserRange(Process::UserRegion::Normal, address, reservedLength);
87 subsystem->
setAbi(PosixSubsystem::LinuxAbi);
88 MuslAmd64Termios* user =
reinterpret_cast<MuslAmd64Termios*
>(address);
89 ByteSet(user, 0xA5,
sizeof(*user) + 16);
90 context->getter = posix_ioctl(TerminalDescriptor, TCGETS, user) == 0 && user->c_line == 0;
91 for (
size_t i = 0; i < LinuxControlCount; ++i) {
92 context->getter &= user->c_cc[i] ==
static_cast<uint8_t
>(defaultControl[i]);
94 for (
size_t i = LinuxTermiosExtent; i <
sizeof(*user) + 16; ++i) {
95 context->getter &=
reinterpret_cast<uint8_t*
>(user)[i] == 0xA5;
98 context->setter =
true;
99 const size_t commands[] = {TCSETS, TCSETSW, TCSETSF};
100 for (
size_t command : commands) {
102 for (
size_t i = 0; i < LinuxControlCount; ++i) {
103 user->c_cc[i] =
static_cast<uint8_t
>(0x21 + i);
105 context->setter &= posix_ioctl(TerminalDescriptor, command, user) == 0;
106 char control[MAX_CONTROL_CHAR] = {};
107 ConsoleManager::instance().getControlChars(context->console, control);
110 for (
size_t i = 0; i < LinuxControlCount; ++i) {
111 context->setter &=
static_cast<uint8_t
>(control[i]) ==
static_cast<uint8_t
>(0x21 + i);
113 context->setter &= control[VINTR] == user->c_cc[VINTR] && control[VEOF] == user->c_cc[VEOF] &&
114 control[VMIN] == user->c_cc[VMIN] && control[VSUSP] == user->c_cc[VSUSP];
117 void* exact =
reinterpret_cast<void*
>(address + pageSize - LinuxTermiosExtent);
118 MemoryCopy(exact, user, LinuxTermiosExtent);
119 context->extent = posix_ioctl(TerminalDescriptor, TCSETS, exact) == 0 &&
120 posix_ioctl(TerminalDescriptor, TCGETS, exact) == 0;
121 void* shortBuffer =
reinterpret_cast<void*
>(address + pageSize - LinuxTermiosExtent + 1);
122 char before[MAX_CONTROL_CHAR] = {};
123 char after[MAX_CONTROL_CHAR] = {};
124 ConsoleManager::instance().getControlChars(context->console, before);
126 context->extent &= posix_ioctl(TerminalDescriptor, TCSETS, shortBuffer) == -1 &&
127 thread->
getErrno() == Error::BadAddress;
128 ConsoleManager::instance().getControlChars(context->console, after);
129 context->extent &= !MemoryCompare(before, after,
sizeof(before));
131 context->extent &= posix_ioctl(TerminalDescriptor, TCGETS, shortBuffer) == -1 &&
132 thread->
getErrno() == Error::BadAddress;
134 subsystem->
setAbi(PosixSubsystem::PosixAbi);
135 LegacyTermios* legacy =
reinterpret_cast<LegacyTermios*
>(address);
136 ByteSet(legacy, 0,
sizeof(*legacy));
137 legacy->c_lflag = ICANON;
138 for (
size_t i = 0; i <
sizeof(legacy->c_cc); ++i) {
139 legacy->c_cc[i] =
static_cast<cc_t
>(0x41 + i);
141 context->legacy = posix_ioctl(TerminalDescriptor, TCSETS, legacy) == 0;
142 ConsoleManager::instance().getControlChars(context->console, after);
143 for (
size_t i = 0; i <
sizeof(legacy->c_cc); ++i) {
144 context->legacy &=
static_cast<cc_t
>(after[i]) == legacy->c_cc[i];
146 ByteSet(legacy, 0,
sizeof(*legacy));
147 context->legacy &= posix_ioctl(TerminalDescriptor, TCGETS, legacy) == 0 &&
148 legacy->c_lflag == ICANON && legacy->c_ispeed == 115200 &&
149 legacy->c_ospeed == 115200;
150 for (
size_t i = 0; i <
sizeof(legacy->c_cc); ++i) {
151 context->legacy &= legacy->c_cc[i] ==
static_cast<cc_t
>(0x41 + i);
155 context->process->freeUserRange(Process::UserRegion::Normal, address, reservedLength);
156 context->returned += 1;
161bool runHostedTermiosSyscallRegressions(
Process* kernelProcess) {
164 process->setSubsystem(subsystem);
168 TermiosContext context{process, console};
169 Thread*
worker =
new Thread(process, termiosWorker, &context,
nullptr,
false,
true,
true);
170 worker->setName(
"hosted termios ABI");
171 const bool started =
worker->start();
172 const bool joined = started &&
worker->joinForCompletion();
176 const bool passed = started && joined && context.returned == 1 && context.getter &&
177 context.setter && context.extent && context.legacy;
181 ERROR(
"HOSTED-SYSCALL-TEST: FAIL termios-linux-amd64-abi: getter="
182 << context.getter <<
", setter=" << context.setter <<
", extent=" << context.extent
183 <<
", legacy=" << context.legacy);
186 NOTICE(
"HOSTED-SYSCALL-TEST: PASS termios-linux-amd64-abi");
Memory-mapped file interface.
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
size_t remove(uintptr_t base, size_t length)
static MemoryMapManager & instance()
static constexpr size_t getPageSize() PURE
void addFileDescriptor(size_t fd, FileDescriptor *pFd)
static ProcessorInformation & information()
void setErrno(size_t err)