From 1d69a46f5d9823bbf2e6211ca367b409d2d5f7a7 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Mon, 1 Mar 2021 22:35:26 -0500 Subject: minimal file writing, shutdown keybinding (Win+Shift+Q) --- src/kernel/drive.c | 28 ++++++-------- src/kernel/drive.h | 3 ++ src/kernel/fat.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++---- src/kernel/fat.h | 2 + src/kernel/ide.c | 78 +++++++++++++++++++++++++++---------- src/kernel/idt.c | 27 ++++++++++++- src/kernel/isrs.asm | 2 +- src/kernel/kbd.c | 4 ++ src/kernel/shutdown.c | 20 ++++++++++ src/kernel/shutdown.h | 6 +++ src/kernel/util.c | 36 +++++++++++++++++ src/kernel/util.h | 1 + src/kernel/window.c | 54 ++++++++++++++++++++++++++ src/kernel/window.h | 2 + 14 files changed, 322 insertions(+), 45 deletions(-) create mode 100644 src/kernel/shutdown.c create mode 100644 src/kernel/shutdown.h (limited to 'src/kernel') diff --git a/src/kernel/drive.c b/src/kernel/drive.c index 2ae050f..8dc0e68 100644 --- a/src/kernel/drive.c +++ b/src/kernel/drive.c @@ -1,6 +1,7 @@ #include "drive.h" #include "panic.h" #include "fat.h" +#include "log.h" uint8_t n_drives; struct drive drives[256]; @@ -14,21 +15,9 @@ static file_id_t unknown_get_file(const struct drive *d, const char *path) { return 0; } -static void unknown_free_file(const struct drive *d, file_id_t fid) { - PANIC("Free file called on unknown file system."); -} - -static void unknown_load_sector(const struct drive *d, file_id_t fid, uint32_t sector, void *at) { - PANIC("Load sector called on unknown file system."); -} - -static uint32_t unknown_get_file_length(const struct drive *d, file_id_t fid) { - PANIC("Get file length called on unknown file system."); -} - __attribute__ ((const)) static uint32_t unknown_get_free_sectors(const struct drive *d) { - return -1; + return 0; } __attribute__ ((const)) @@ -41,15 +30,22 @@ static uint32_t unknown_n_dir_entries(const struct drive *d, const char *path) { return 0; } +static void unknown_no_call(const struct drive *d) { + logf(LOG_ERROR, "file-level operation called on drive %u (%s), which is an unknown file system", d - drives + 1, d->fs_type); +} + static inline void determine_fs(struct drive *d) { if (try_fat_init_drive(d)) return; d->fs_type = "Unknown"; d->get_file = &unknown_get_file; - d->free_file = &unknown_free_file; - d->load_sector = &unknown_load_sector; - d->get_file_length = &unknown_get_file_length; + d->free_file = &unknown_no_call; + d->load_sector = &unknown_no_call; + d->save_sector = &unknown_no_call; + d->is_writable = &unknown_no_call; + d->get_file_length = &unknown_no_call; + d->set_file_length = &unknown_no_call; d->enumerate_dir = &unknown_enumerate_dir; d->n_dir_entries = &unknown_n_dir_entries; d->get_free_sectors = &unknown_get_free_sectors; diff --git a/src/kernel/drive.h b/src/kernel/drive.h index 03fe4b6..93811e8 100644 --- a/src/kernel/drive.h +++ b/src/kernel/drive.h @@ -33,7 +33,10 @@ struct drive { file_id_t (*get_file) (const struct drive *d, const char *path); void (*free_file) (const struct drive *d, file_id_t fid); void (*load_sector) (const struct drive *d, file_id_t fid, uint32_t sector, void *at); + void (*save_sector) (const struct drive *d, file_id_t fid, uint32_t sector, const void *from); + bool (*is_writable) (const struct drive *d, file_id_t fid); uint32_t (*get_file_length) (const struct drive *d, file_id_t fid); + void (*set_file_length) (const struct drive *d, file_id_t fid, uint32_t new_len); uint32_t (*enumerate_dir) (const struct drive *d, const char *path, struct directory_content_info *info, uint32_t max); uint32_t (*n_dir_entries) (const struct drive *d, const char *path); uint32_t (*get_free_sectors)(const struct drive *d); diff --git a/src/kernel/fat.c b/src/kernel/fat.c index 5ba62cf..b865859 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -3,6 +3,7 @@ #include "util.h" #include "ata.h" #include "fat.h" +#include "log.h" #include "pmap.h" #define MAX_FAT_DRIVES 16 @@ -18,14 +19,17 @@ enum { FA_LABEL = 0x08, FA_DIRECTORY = 0x10, FA_ARCHIVE = 0x20, +}; - FA_LFN = 0x0f +enum { + //applied to every file without FA_READ_ONLY + FEA_OPEN_EXCLUSIVE = 0x01 }; struct directory_entry { uint8_t name[11]; uint8_t attrib; - uint8_t name_case; + uint8_t extra_attrib;//non-standard attributes uint8_t created_decimal; uint16_t created_time; uint16_t created_date; @@ -70,9 +74,12 @@ struct open_file_info { uint16_t start_cluster; uint32_t length; + + uint8_t attrib; }; struct fat_drive_info { + const struct drive *from_drive; const struct fat_info *fi; uint16_t *fat; uint16_t root_start; @@ -109,6 +116,11 @@ static void load_cluster(uint16_t c, void *to) { cur_drive->read_sectors(cur_drive, s, 1, to); } +static void save_cluster(uint16_t c, const void *from) { + uint32_t s = CTOS(c, cur_fdi); + cur_drive->write_sectors(cur_drive, s, 1, from); +} + __attribute__ ((pure)) static uint16_t next_cluster(uint16_t c) { uint16_t found = infos[cur_id].fat[c]; @@ -226,22 +238,47 @@ static file_id_t fat_get_file(const struct drive *d, const char *path) { return 0; } + if (cur_dir->extra_attrib & FEA_OPEN_EXCLUSIVE) { + d->done(d); + return 0;//maybe have a special return value for this? + } + + if (!(cur_dir->attrib & FA_READ_ONLY)) { + cur_dir->extra_attrib |= FEA_OPEN_EXCLUSIVE; + d->write_sectors(d, cur_sect, 1, fat_driver_buffer); + } + d->done(d); + open_files[n].di_sector = cur_sect; open_files[n].di_number = cur_dir - (struct directory_entry *)fat_driver_buffer; open_files[n].start_cluster = cur_dir->first_cluster; open_files[n].length = cur_dir->length; + open_files[n].attrib = cur_dir->attrib; + return n; } - PANIC("Maximum number of files open reached for FAT drive."); + d->done(d); + logf(LOG_ERROR, "Maximum number of open files (%d) reached for drive %u (%s, FAT).", MAX_OPEN_FILES_PER_DRIVE, d - drives + 1, d->drive_type); + return 0; } static void fat_free_file(const struct drive *d, file_id_t fid) { - infos[d->drive_id].open_files[fid - 1].di_sector = 0; + struct open_file_info *const of = infos[d->drive_id].open_files + fid - 1; + + if (!(of->attrib & FA_READ_ONLY)) { + d->ready(d); + d->read_sectors(d, of->di_sector, 1, fat_driver_buffer); + ((struct directory_entry *)fat_driver_buffer)[of->di_number].extra_attrib &= ~FEA_OPEN_EXCLUSIVE; + d->write_sectors(d, of->di_sector, 1, fat_driver_buffer); + d->done(d); + } + + of->di_sector = 0; } -static void fat_load_sector(const struct drive *d, file_id_t fid, uint32_t sector, void *at) { +static uint16_t get_nth_cluster(const struct drive *d, file_id_t fid, uint32_t sector) { cur_drive = d; cur_id = d->drive_id; cur_fdi = &infos[cur_id]; @@ -250,16 +287,48 @@ static void fat_load_sector(const struct drive *d, file_id_t fid, uint32_t secto for (uint32_t i = 0; i < sector; ++i) c = next_cluster(c); + return c; +} + +static void fat_load_sector(const struct drive *d, file_id_t fid, uint32_t sector, void *at) { + uint16_t c = get_nth_cluster(d, fid, sector); + d->ready(d); load_cluster(c, at); d->done(d); } +static void fat_save_sector(const struct drive *d, file_id_t fid, uint32_t sector, const void *from) { + if (infos[d->drive_id].open_files[fid - 1].attrib & FA_READ_ONLY) + return;//maybe return special value for this + + uint16_t c = get_nth_cluster(d, fid, sector); + + d->ready(d); + save_cluster(c, from); + d->done(d); +} + __attribute__ ((pure)) static uint32_t fat_get_file_length(const struct drive *d, file_id_t fid) { return infos[d->drive_id].open_files[fid - 1].length; } +static void fat_set_file_length(const struct drive *d, file_id_t fid, uint32_t new_length) { + struct open_file_info *const of = infos[d->drive_id].open_files + fid - 1; + if (of->attrib & FA_READ_ONLY) + return;//maybe return special vlue for this + + if (((new_length - 1) >> 9) + 1 != ((of->length - 1) >> 9) + 1) + PANIC("TODO: resizing FAT file to different sector count"); + + of->length = new_length; + + d->read_sectors(d, of->di_sector, 1, fat_driver_buffer); + ((struct directory_entry *)fat_driver_buffer)[of->di_number].length = new_length; + d->write_sectors(d, of->di_sector, 1, fat_driver_buffer); +} + __attribute__ ((pure)) static uint32_t fat_get_free_sectors(const struct drive *d) { uint16_t *start = infos[d->fs_id].fat + 2; @@ -429,6 +498,11 @@ static uint32_t fat_n_dir_entries(const struct drive *d, const char *path) { } } +__attribute__ ((__pure__)) +static bool fat_is_writable(const struct drive *d, file_id_t fid) { + return !(infos[d->drive_id].open_files[fid - 1].attrib & FA_READ_ONLY); +} + void init_fat() { next_fi = allocate_kernel_pages(1); next_id = 0; @@ -450,25 +524,41 @@ bool try_fat_init_drive(struct drive *d) { d->get_file = &fat_get_file; d->free_file = &fat_free_file; d->load_sector = &fat_load_sector; + d->save_sector = &fat_save_sector; d->get_file_length = &fat_get_file_length; + d->set_file_length = &fat_set_file_length; d->enumerate_dir = &fat_enumerate_dir; d->n_dir_entries = &fat_n_dir_entries; d->get_free_sectors = &fat_get_free_sectors; + d->is_writable = &fat_is_writable; d->fs_id = next_id; infos[next_id].fi = next_fi; infos[next_id].fat = allocate_kernel_pages(((next_fi->sectors_per_fat - 1) >> 3) + 1); - infos[next_id].root_start = next_fi->reserved_sectors + + infos[next_id].root_start = next_fi->reserved_sectors + next_fi->sectors_per_fat * next_fi->fats; infos[next_id].data_start = infos[next_id].root_start + ((next_fi->root_entries - 1) >> 4) + 1; + logf(LOG_INFO, "0x%h <- 0x%h", &infos[next_id].from_drive, drives + n_drives); + infos[next_id].from_drive = drives + n_drives; d->read_sectors(d, next_fi->reserved_sectors, next_fi->sectors_per_fat, infos[next_id].fat); - struct open_file_info *open_files = infos[next_id].open_files - 1; + struct open_file_info *open_files = infos[next_id].open_files; for (file_id_t i = 0; i < MAX_OPEN_FILES_PER_DRIVE; ++i) open_files[i].di_sector = 0; alloc_next_fi(); ++next_id; return true; +} + +void fat_ready_shutdown() { + for (uint8_t i = 0; i < next_id; ++i) + for (uint8_t j = 0; j < MAX_OPEN_FILES_PER_DRIVE; ++j) + if (infos[i].open_files[j].di_sector) { + logf(LOG_INFO, "i = %d, j = %d", i, j); + logf(LOG_INFO, "freeing file %d from drive 0x%h (number %d)", j + 1, infos[i].from_drive, infos[i].from_drive - drives + 1); + logf(LOG_INFO, "0x%h -> 0x%h", &infos[i].from_drive, infos[i].from_drive); + fat_free_file(infos[i].from_drive, j + 1); + } } \ No newline at end of file diff --git a/src/kernel/fat.h b/src/kernel/fat.h index 3ca9cc3..364b3db 100644 --- a/src/kernel/fat.h +++ b/src/kernel/fat.h @@ -8,4 +8,6 @@ void init_fat(); bool try_fat_init_drive(struct drive *d); +void fat_ready_shutdown(); + #endif \ No newline at end of file diff --git a/src/kernel/ide.c b/src/kernel/ide.c index 39525ad..1f7df10 100644 --- a/src/kernel/ide.c +++ b/src/kernel/ide.c @@ -4,6 +4,7 @@ #include "panic.h" #include "util.h" #include "ata.h" +#include "log.h" #include "pci.h" #define MAX_IDE_DRIVES 8 @@ -17,7 +18,7 @@ struct ide_drive_info { static struct ide_drive_info ide_drives[MAX_IDE_DRIVES]; static drive_id_t n_ide_drives; -typedef uint16_t spinner_t; +typedef uint32_t spinner_t; //returns the status after waiting static uint8_t wait_for_ready(uint16_t base_port) { @@ -31,6 +32,17 @@ static uint8_t wait_for_ready(uint16_t base_port) { PANIC("Spun out in IDE driver."); } +static void wait_for_not_busy(uint16_t base_port) { + for (spinner_t n = -1; n; --n) { + uint8_t s = inb(base_port | ATA_REG_STATUS); + if (s & ATA_STATUS_ERROR) + PANIC("Error status in IDE driver."); + if (!(s & ATA_STATUS_BUSY)) + return; + } + PANIC("Spun out in IDE driver."); +} + //returns the status after waiting static uint8_t wait_for_error_or_ready(uint16_t base_port) { for (spinner_t n = -1; n; --n) { @@ -53,6 +65,21 @@ static uint8_t wait_for_data_ready_not_busy(uint16_t base_port) { PANIC("Spun out in IDE driver."); } +static void prepare_ata_access(uint16_t port, bool slave, uint32_t lba, uint32_t count) { + if (lba & 0xf0000000) + PANIC("IDE ATA driver does not support reads starting past 128GiB currently."); + if (count & 0xffffff00) + PANIC("IDE ATA driver does not support reads over 128kiB in length currently."); + + outb(port | ATA_REG_SELECT, (slave ? 0xf0 : 0xe0) | (lba >> 24)); + //spin? + + outb(port | ATA_REG_COUNT, count); + outb(port | ATA_REG_LBA0, lba); + outb(port | ATA_REG_LBA1, lba >> 8); + outb(port | ATA_REG_LBA2, lba >> 16); +} + static uint32_t ide_ata_rs(const struct drive *d, uint32_t start, uint32_t count, void *buffer) { if (start >= d->n_sectors) return 0; @@ -61,38 +88,49 @@ static uint32_t ide_ata_rs(const struct drive *d, uint32_t start, uint32_t count if (!count) return 0; - if (start & 0xf0000000) - PANIC("IDE ATA driver does not support reads starting past 256MiB currently."); - if (count & 0xffffff00) - PANIC("IDE ATA driver does not support reads over 128kiB in length currently."); - - uint32_t lba = start & 0x00ffffff; - - struct ide_drive_info *info = ide_drives + d->drive_id; - - outb(info->base_port | ATA_REG_SELECT, (info->slave ? 0xf0 : 0xe0) | (start >> 24)); - //spin? - - outb(info->base_port | ATA_REG_COUNT, count); - outb(info->base_port | ATA_REG_LBA0, lba); - outb(info->base_port | ATA_REG_LBA1, lba >> 8); - outb(info->base_port | ATA_REG_LBA2, lba >> 16); + const struct ide_drive_info *const info = ide_drives + d->drive_id; + prepare_ata_access(info->base_port, info->slave, start, count); outb(info->base_port | ATA_REG_CMD, ATA_CMD_READ); uint16_t *buf16 = (uint16_t *)buffer; - for (uint16_t i = 0; i < count; ++i) { + for (uint32_t i = 0; i < count; ++i) { wait_for_data_ready_not_busy(info->base_port); for (uint16_t j = 0; j < 256; ++j) - *buf16++ = inw(info->base_port | ATA_REG_DATA); + *(buf16++) = inw(info->base_port | ATA_REG_DATA); } return count; } static uint32_t ide_ata_ws(const struct drive *d, uint32_t start, uint32_t count, const void *buffer) { - PANIC("IDE ATA writing not implemented yet."); + if (start >= d->n_sectors) + return 0; + if (start + count > d->n_sectors) + count = d->n_sectors - start; + if (!count) + return 0; + +//logf(LOG_INFO, "writing IDE sectors: 0x%h - 0x%h", start * 512, start * 512 + count * 512 - 1); + + const struct ide_drive_info *const info = ide_drives + d->drive_id; + + prepare_ata_access(info->base_port, info->slave, start, count); + outb(info->base_port | ATA_REG_CMD, ATA_CMD_WRITE); + + const uint16_t *buf16 = (const uint16_t *)buffer; + + for (uint32_t i = 0; i < count; ++i) { + wait_for_not_busy(info->base_port); + for (uint16_t j = 0; j < 256; ++j) + outw(info->base_port | ATA_REG_DATA, *(buf16++)); + } + + outb(info->base_port | ATA_REG_CMD, ATA_CMD_FLUSH); + wait_for_not_busy(info->base_port); + + return count; } static uint32_t ide_atapi_rs(const struct drive *d, uint32_t start, uint32_t count, void *buffer) { diff --git a/src/kernel/idt.c b/src/kernel/idt.c index c79ae7b..1a78da0 100644 --- a/src/kernel/idt.c +++ b/src/kernel/idt.c @@ -52,6 +52,12 @@ uint32_t sc_file_get_size(uint32_t handle) { return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff); } +void sc_file_set_size(uint32_t handle, uint32_t new_size) { + if (!handle) + return; + drives[handle >> 8].set_file_length(drives + (handle >> 8), handle & 0xff, new_size); +} + uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { if (!handle) return 0; @@ -62,6 +68,23 @@ uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, voi return count; } +uint32_t sc_file_write(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { + if (!handle) + return 0; + const struct drive *const d = drives + (handle >> 8); + const fs_id_t fid = handle & 0xff; + + if (!d->is_writable(d, fid)) + return 0; + + const uint32_t l = d->get_file_length(d, fid); + if (file_offset + count > l) + count = l - file_offset; + + mfcpy(d, fid, file_offset, buffer, count); + return count; +} + uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t io_task) { switch_to_kernel_cr3(); uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass, io_task); @@ -183,7 +206,9 @@ void const *syscall_table[] = { &find_unread_ipc, &sc_wait_ipc_read, &sc_is_task_running, - &sc_get_timestamp + &sc_get_timestamp, + &sc_file_write, + &sc_file_set_size }; //these aren't really void ()'s, but gcc complains if we take an address of a void, so we give it a type diff --git a/src/kernel/isrs.asm b/src/kernel/isrs.asm index f547bfb..1aba884 100644 --- a/src/kernel/isrs.asm +++ b/src/kernel/isrs.asm @@ -25,7 +25,7 @@ extern exception_halt extern pf_check_stack extern dump -n_syscalls equ 0x1a +n_syscalls equ 0x1c ;section .bss ;_debug_is_start_task resb 1 diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c index 96d2069..47894cd 100644 --- a/src/kernel/kbd.c +++ b/src/kernel/kbd.c @@ -1,6 +1,7 @@ #include #include "settings.h" +#include "shutdown.h" #include "window.h" #include "drive.h" #include "panic.h" @@ -221,6 +222,9 @@ enum kbd_isr_result on_kbd_isr() { if (!is_up && (entry == KEY_PAUSE) && (keymods & ALTS)) return (keymods & SHIFTS) ? SHIFT_DUMP : DUMP; + if (!is_up && (entry == KEY_Q) && (keymods & WINS) && (keymods & SHIFTS)) + shutdown(); + on_action((struct window_action){ .action_type = is_up ? KEY_UP : KEY_DOWN, .as_key = (struct key_packet){ diff --git a/src/kernel/shutdown.c b/src/kernel/shutdown.c new file mode 100644 index 0000000..9f7ccc7 --- /dev/null +++ b/src/kernel/shutdown.c @@ -0,0 +1,20 @@ +#include "paging.h" +#include "window.h" +#include "fat.h" +#include "log.h" + +__attribute__ ((noreturn)) +void shutdown() { + logf(LOG_INFO, "Shutting down..."); + + asm ("cli"); + switch_to_kernel_cr3(); + + fat_ready_shutdown(); + + logf(LOG_INFO, "Finished getting ready for shutdown."); + + show_shutdown(); + while (1) + asm ("hlt"); +} \ No newline at end of file diff --git a/src/kernel/shutdown.h b/src/kernel/shutdown.h new file mode 100644 index 0000000..2a76e64 --- /dev/null +++ b/src/kernel/shutdown.h @@ -0,0 +1,6 @@ +#ifndef SHUTDOWN_H +#define SHUTDOWN_H + +void shutdown() __attribute__ ((noreturn)); + +#endif \ No newline at end of file diff --git a/src/kernel/util.c b/src/kernel/util.c index ea0496e..279616c 100644 --- a/src/kernel/util.c +++ b/src/kernel/util.c @@ -2,7 +2,15 @@ #include #include "drive.h" +#include "log.h" +#define ACROSS 0x04004e60 + void memcpy(void *to, const void *from, uint32_t n) { + if (((uint32_t)to <= ACROSS) && ((uint32_t)(to + n) > ACROSS)) { + logf(LOG_WARN, "memcpy across 0x%h!", ACROSS); + logf(LOG_INFO, "was: memcpy(0x%h, 0x%h, %d)", to, from, n); + } + uint32_t *tp = to; const uint32_t *fp = from; while (n >= 4) { @@ -39,4 +47,32 @@ void fmcpy(void *to, const struct drive *d, file_id_t f, uint32_t from, uint32_t d->load_sector(d, f, fsi, buf); memcpy(to + i, buf, n); +} + +void mfcpy(const struct drive *d, file_id_t f, uint32_t to, const void *from, uint32_t n) { + uint8_t buf[512]; + + const uint16_t first_batch = to % 512 + n >= 512 ? 512 - to % 512 : n; + if (first_batch) { + d->load_sector(d, f, to / 512, buf); + memcpy(buf + to % 512, from, first_batch); + d->save_sector(d, f, to / 512, buf); + n -= first_batch; + from += first_batch; + } + + uint32_t sector_on = to / 512 + 1; + while (n >= 512) { + memcpy(buf, from, 512); + d->save_sector(d, f, sector_on, buf); + n -= 512; + from += 512; + ++sector_on; + } + + if (n) { + d->load_sector(d, f, sector_on, buf); + memcpy(buf, from, n); + d->save_sector(d, f, sector_on, buf); + } } \ No newline at end of file diff --git a/src/kernel/util.h b/src/kernel/util.h index c5b784a..2500904 100644 --- a/src/kernel/util.h +++ b/src/kernel/util.h @@ -43,6 +43,7 @@ static inline uint32_t ind(uint16_t port) { void memcpy(void *to, const void *from, uint32_t n); void fmcpy(void *to, const struct drive *d, file_id_t f, uint32_t from, uint32_t n); +void mfcpy(const struct drive *d, file_id_t f, uint32_t to, const void *from, uint32_t n); uint8_t u32_dec(uint32_t n, char *b); uint8_t u16_dec(uint16_t n, char *b); diff --git a/src/kernel/window.c b/src/kernel/window.c index 79d718e..1c4eb26 100644 --- a/src/kernel/window.c +++ b/src/kernel/window.c @@ -82,6 +82,60 @@ static void blit() { } } +#define POWER_OFF_MESSAGE_PITCH 45 +#define POWER_OFF_MESSAGE_ROWS 28 +static const bool power_off_message[] = { + 1,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1, + 1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1, + 0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1,0,0,0,1,0,0,0,1,0,1,0, + 0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,0,1,0,1,0, + 0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, + 0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,1,0,0,1,1,1,1,1,0,0,1,0,0,0,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +#define POWER_OFF_SCALE 3 + +void show_shutdown() { + for (uint32_t i = 0; i < VBE_MODE_INFO->height * VBE_MODE_INFO->width; ++i) + buffer[i] = (struct pixel){.r = 0, .g = 0, .b = 0}; + + const uint16_t x_pad = (VBE_MODE_INFO->width - POWER_OFF_MESSAGE_PITCH * POWER_OFF_SCALE) / 2; + const uint16_t y_pad = (VBE_MODE_INFO->height - POWER_OFF_MESSAGE_ROWS * POWER_OFF_SCALE) / 2; + + for (uint8_t r = 0; r < POWER_OFF_MESSAGE_ROWS; ++r) + for (uint8_t i = 0; i < POWER_OFF_MESSAGE_PITCH; ++i) + if (power_off_message[r * POWER_OFF_MESSAGE_PITCH + i]) { + const uint32_t o = x_pad + i * POWER_OFF_SCALE + (y_pad + r * POWER_OFF_SCALE) * VBE_MODE_INFO->width; + for (uint8_t y = 0; y < POWER_OFF_SCALE; ++y) + for (uint8_t x = 0; x < POWER_OFF_SCALE; ++x) + buffer[o + x + y * VBE_MODE_INFO->width] = (struct pixel){.r = 255, .g = 255, .b = 255}; + } + + blit(); +} + static inline void draw_hz_line(uint16_t y, uint16_t xs, uint16_t xm, struct pixel color) { if (y >= VBE_MODE_INFO->height) return; diff --git a/src/kernel/window.h b/src/kernel/window.h index ebd0496..0a83845 100644 --- a/src/kernel/window.h +++ b/src/kernel/window.h @@ -31,4 +31,6 @@ void on_action(struct window_action packet); void delete_any_windows_from(struct task_state *tstate); +void show_shutdown(); + #endif -- cgit v1.2.3