1
0
Fork 0
mirror of https://gitlab.com/niansa/minituxi.git synced 2025-03-06 20:49:18 +01:00

Lots and lots of fixups and cleanups, basic framebuffer stuff

This commit is contained in:
Nils 2021-08-07 23:52:27 +02:00
parent a69319e942
commit 006d62ed76
9 changed files with 2220 additions and 41 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
bin
bzImage
CMakeLists.txt.user
initramfs.cpio.gz

27
CMakeLists.txt Normal file
View file

@ -0,0 +1,27 @@
# Created by and for Qt Creator This file was created for editing the project sources only.
# You may attempt to use it for building too, by modifying this file here.
cmake_minimum_required(VERSION 3.5)
project(minituxi)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(
include
)
set(SRCS
include/defs.h
include/system.hpp
include/font.hpp
src/main.cpp
src/system.cpp
src/font.cpp
)
add_executable(${CMAKE_PROJECT_NAME} ${SRCS})
target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC pthread)

View file

@ -1,10 +1,14 @@
all: genimg
compile:
mkdir -p bin
utils/compile.sh
genimg: compile
utils/genimg.sh
test:
qemu-system-x86_64 -hda /dev/null -m 64 -kernel bzImage -initrd initramfs.cpio.gz -append 'quiet rdinit=/main'
qemu-system-x86_64 -hda /dev/null -m 128 -kernel bzImage -initrd initramfs.cpio.gz -append 'quiet rdinit=/main'
clean:
cat .gitignore | xargs rm -rfv

View file

21
include/font.hpp Normal file
View file

@ -0,0 +1,21 @@
#include <span>
namespace Font {
constexpr unsigned int height = 16,
width = 8;
constexpr unsigned int size = height * width;
using Letter = std::span<const bool>;
extern const bool fontBitmapUnk[size];
Letter getChar(const char character);
inline Letter getUnk() {
return Letter{fontBitmapUnk, size};
}
}

View file

@ -1,66 +1,233 @@
#ifndef _SYSTEM_HPP
#define _SYSTEM_HPP
#include <iostream>
#include <string_view>
#include <fstream>
#include <filesystem>
#include <functional>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/sysinfo.h>
#include <sys/mount.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <linux/input.h>
namespace System {
[[noreturn]]
void lockup();
namespace get_mem {
size_t total() {
// Get sysinfo
struct sysinfo i;
sysinfo(&i);
// Get total ram
return i.totalram;
}
size_t free() {
// Get sysinfo
struct sysinfo i;
sysinfo(&i);
// Get available ram
return i.freeram;
}
size_t used() {
// Get sysinfo
struct sysinfo i;
sysinfo(&i);
// Get used ram
return i.totalram - i.freeram;
[[noreturn]]
void critical_stop(std::string_view msg);
template<typename T>
inline T check_sysc(T v, std::string_view msg = "Syscall failed") {
if (v < 0) {
critical_stop(msg);
}
return v;
}
class SysInfo {
struct sysinfo i;
public:
SysInfo() {
check_sysc(sysinfo(&i), "Failed to obtain sysinfo");
}
const struct sysinfo& get() const {
return i;
}
};
class Mounts {
public:
Mounts() {
std::filesystem::create_directory("/dev");
mount("devtmpfs", "/dev", "devtmpfs", 0, 0);
std::filesystem::create_directory("/proc");
check_sysc(mount("devtmpfs", "/dev", "devtmpfs", 0, 0), "Failed to initialize devices filesystem");
check_sysc(mount("proc", "/proc", "proc", 0, 0), "Failed to initialize process filesystem");
}
~Mounts() {
umount("/dev");
check_sysc(umount("/dev"), "Failed to deinitialize devices filesystem");
check_sysc(umount("/proc"), "Failed to deinitialize process filesystem");
}
};
class Console {
class TermAntiFlagger {
termios termbak;
public:
Console(tcflag_t antiflags) {
TermAntiFlagger(tcflag_t antiflags) {
termios thisterm;
tcgetattr(0, &thisterm);
termbak = thisterm;
thisterm.c_lflag &= ~antiflags;
tcsetattr(0, TCSANOW, &thisterm);
}
~Console() {
~TermAntiFlagger() {
tcsetattr(0, TCSANOW, &termbak);
}
};
class Framebuffer {
using pixType = uint32_t;
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
int fb_fd;
pixType *buf; // Slow real buffer
pixType *dBuf; // Fast double buffer
size_t bufSize; // In bytes!!!
size_t bufArrSize; // In pixels
public:
Framebuffer() {
// Open framebuffer
fb_fd = check_sysc(open("/dev/fb0", O_RDWR), "Unable to access framebuffer");
// Collect information
ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);
ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);
bufArrSize = vinfo.xres * vinfo.yres;
bufSize = sizeof(pixType) * bufArrSize;
// Map memory
buf = reinterpret_cast<pixType*>(mmap(nullptr, bufSize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0));
dBuf = new pixType[bufSize];
}
~Framebuffer() {
// Unmap memory
munmap(buf, bufSize);
delete []dBuf;
// Close framebuffer
close(fb_fd);
}
const auto& get_finfo() const {
return finfo;
}
const auto& get_vinfo() const {
return vinfo;
}
bool inBounds(size_t idx) {
return idx < bufArrSize;
}
pixType& operator[](size_t idx) {
return dBuf[idx];
}
void display() {
memcpy(buf, dBuf, bufSize);
}
void draw(uint x, uint y, pixType color) {
if (x < vinfo.xres && y < vinfo.yres) {
dBuf[y * vinfo.xres + x] = color;
}
}
void fill(pixType color) {
for (size_t idx = 0; inBounds(idx); idx++) {
dBuf[idx] = color;
}
}
void draw_text(std::string_view str, uint x, uint y, pixType color = 0xFFFFFF);
void draw_horizontal_line(uint x1, uint x2, uint y, pixType color) {
for (uint i = x1; i < x2; i++) {
draw(i, y, color);
}
}
void draw_vertical_line(uint x, uint y1, uint y2, pixType color) {
for (uint i = y1; i < y2; i++) {
draw(x, i, color);
}
}
void draw_line(uint x1, uint y1, uint x2, uint y2, pixType color);
void draw_circle(double cx, double cy, uint radius, pixType color, bool filled = false);
};
class Mouse {
int mouse_fd;
public:
struct Event {
struct input_event base;
enum {
MOUSEX,
MOUSEY,
WHEEL,
BUTTON
} type;
int32_t value;
Event(struct input_event& base) : base(base) {
switch (base.type) {
case 2: {
switch (base.code) {
case 0: type = MOUSEX; break;
case 1: type = MOUSEY; break;
case 11: type = WHEEL; break;
}
} break;
case 4: type = BUTTON; break;
}
value = base.value;
}
};
Mouse() {
// Find mouse
std::filesystem::path mouseEventPath;
for (const auto& f : std::filesystem::directory_iterator("/dev/input/by-path/")) {
auto& path = f.path();
if (f.path().filename().generic_string().ends_with("-event-mouse")) {
mouseEventPath = f.path();
}
}
// Check that a mouse was found
if (mouseEventPath.empty()) {
mouse_fd = -1;
} else {
// Open mice
mouse_fd = check_sysc(open(mouseEventPath.c_str(), O_RDWR), "Unable to access mouse");
// Gain exclusive access
check_sysc(ioctl(mouse_fd, EVIOCGRAB, 1), "Failed to gain exclusive access over mouse");
}
}
bool connected() {
return mouse_fd != -1;
}
Event event_wait() {
if (!connected()) {
lockup();
}
struct input_event ev;
read(mouse_fd, &ev, sizeof(ev));
return Event(ev);
}
};
}
#endif

1763
src/font.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,21 +1,86 @@
#include "system.hpp"
#include "font.hpp"
#include <iostream>
#include <string>
#include <filesystem>
#include "system.hpp"
using namespace std;
#include <vector>
#include <mutex>
#include <exception>
#include <thread>
#include <chrono>
using namespace std::literals::chrono_literals;
int main() {
{
// Initialisations
Mounts mounts;
struct UMain {
std::mutex mutex;
System::Framebuffer fb;
System::Mouse mouse;
struct {uint x = 100, y = 100;} mousePos;
// Print memory usage
cout << "Total: " << get_mem::total() / 1000000 << " MB" << endl
<< "Used: " << get_mem::used() / 1000000 << " MB" << endl
<< "Free: " << get_mem::free() / 1000000 << " MB" << endl;
void poll() {
// Update mouse position
auto ev = mouse.event_wait();
mutex.lock();
switch (ev.type) {
case System::Mouse::Event::MOUSEX: mousePos.x += ev.value; break;
case System::Mouse::Event::MOUSEY: mousePos.y += ev.value; break;
default: break;
}
mutex.unlock();
}
while (1);
void pollLoop() {
while (true) {
poll();
}
}
void drawLoop() {
while (true) {
mutex.unlock();
std::this_thread::sleep_for(15ms);
mutex.lock();
// Clear screen
fb.fill(0x000000);
// Draw stuff
fb.draw_circle(100, 100, 50, 0xFF0000, true);
fb.draw_horizontal_line(0, 100, 100, 0x0000FF);
fb.draw_text("Hello world!", 250, 250);
// Draw mouse
fb.draw_circle(mousePos.x, mousePos.y, 5, 0xFFFFFF, true);
fb.draw_text("This is the cursor", mousePos.x + 20, mousePos.y - Font::height / 2, 0x00FF00);
// Display
fb.display();
}
}
void run() {
std::thread pollThread([this] () {
pollLoop();
});
drawLoop();
}
};
int main() {
std::cout << "\033[H\033[J" << std::flush;
// Initialisations if PID 1 then run
try {
if (getpid() == 1) {
System::Mounts mounts;
UMain().run();
} else {
UMain().run();
}
} catch (std::exception& e) {
System::critical_stop(e.what());
} catch (...) {
System::critical_stop("Unknown");
}
// Lock up
System::lockup();
}

128
src/system.cpp Normal file
View file

@ -0,0 +1,128 @@
#include "system.hpp"
#include "font.hpp"
namespace System {
[[noreturn]]
void lockup() {
std::cout << std::flush;
std::cerr << std::flush;
if (getpid() == 1) {
while(1) usleep(-1);
} else {
abort();
}
}
[[noreturn]]
void critical_stop(std::string_view msg) {
std::cerr << "\n\n\n"
"A critical stop has occured: \n"
"Message: " << msg << "\n"
"Errno: " << strerror(errno) << std::endl;
lockup();
}
void Framebuffer::draw_text(std::string_view str, uint x, uint y, pixType color) {
for (const auto c : str) {
// Get bitmap
auto bitmap = Font::getChar(c);
// Render
int rx = 0;
int ry = 0;
for (const auto pixel : bitmap) {
if (rx == Font::width) {
rx = 0;
ry++;
}
if (ry == Font::height) {
break;
}
if (pixel) {
draw(x + rx, y + ry, color);
}
rx++;
}
// Increase x
x += Font::width;
}
}
void Framebuffer::draw_line(uint x1, uint y1, uint x2, uint y2, pixType pixel) {
// Deltas
int dx = x2 - x1;
int dy = y2 - y1;
// Absolute deltas
uint dxabs = abs(dx);
uint dyabs = abs(dy);
// Signed deltas
int sdx = (dx>0)?1:-1;
int sdy = (dy>0)?1:-1;
// Misc stuff
int x = dyabs / 2;
int y = dxabs / 2;
int px = x1;
int py = y1;
if (dxabs>=dyabs) {
for (int i = 0; i < dxabs; i++) {
y += dyabs;
if (y >= dxabs) {
y -= dxabs;
py += sdy;
}
px += sdx;
draw(px,py,pixel);
}
} else {
for (int i = 0; i < dyabs; i++) {
x += dxabs;
if (x >= dyabs) {
x -= dyabs;
px += sdx;
}
py += sdy;
draw(px,py,pixel);
}
}
}
void Framebuffer::draw_circle(double cx, double cy, uint radius, pixType color, bool filled) {
auto plot4points = [&] (double x, double y) {
if (filled) {
draw_horizontal_line(cx - x, cx + x, cy + y, color);
draw_horizontal_line(cx - x, cx + x, cy - y, color);
} else {
draw(cx + x, cy + y, color);
draw(cx - x, cy + y, color);
draw(cx + x, cy - y, color);
draw(cx - x, cy - y, color);
}
};
auto plot8points = [&] (double x, double y) {
plot4points(x, y);
plot4points(y, x);
};
int error = -radius;
double x = radius;
double y = 0;
while (x >= y) {
plot8points(x, y);
error += y;
y++;
error += y;
if (error >= 0) {
error += -x;
x--;
error += -x;
}
}
}
}