mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2024-11-24 14:56:51 -08:00
this includes more fixes for the bootloader and implementing more of the vga driver, idt, and keyboard driver in preparation for working on the kernel.
This commit is contained in:
parent
a332daa215
commit
5ff47dde28
BIN
.vscode/browse.vc.db
vendored
BIN
.vscode/browse.vc.db
vendored
Binary file not shown.
BIN
.vscode/browse.vc.db-shm
vendored
BIN
.vscode/browse.vc.db-shm
vendored
Binary file not shown.
BIN
.vscode/browse.vc.db-wal
vendored
BIN
.vscode/browse.vc.db-wal
vendored
Binary file not shown.
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -108,6 +108,6 @@
|
||||
"*.json": "default",
|
||||
"*.asm": "default"
|
||||
},
|
||||
"C_Cpp.default.intelliSenseMode": "linux-clang-x86",
|
||||
"C_Cpp.default.intelliSenseMode": "linux-gcc-x86",
|
||||
"cmake.cmakePath": "/usr/bin/cmake"
|
||||
}
|
17
ask.txt
17
ask.txt
@ -1,4 +1,6 @@
|
||||
I am making an x86 32 bit IA32 Operating System in Visual Studio Code 1.81 for Debian Linux. This will not a linux based OS. The system I am developing on has a Intel i7-3770k and is an x86_64 bit and runs Debian 10 Buster Linux with Linux Kernel version 4.19.0-25-amd64 (supports UNIX 98 PTY) and Bash 5.0.3 and the drive has an ext4 partition and a tempfs partition. I have the extension ms-vscode.cpptools installed on VSCode. I also have both gcc 8.3.0 and clang 7.0.1-8+deb10u2 installed. All of my compilers, debuggers, linkers are in /usr/bin. I have Coreutils 8.30, Binutils 2.31.1, Bison 3.3.2, Diffutils 3.7, Findutils 4.6.0.225, Gawk 4.2.1, Grep 3.3, Gzip 1.9, M4 1.4.18, Make 4.2.1, Patch 2.7.6, Perl 5.28.1, Python 3.7.3, Sed 4.7, Tar 1.30, Texinfo 6.5, Xz 5.2.4. The operating system would run on any system that has a 386 CPU up to a Pentium 4.
|
||||
I am making a fully custom x86 32 bit IA32 Operating System in Visual Studio Code 1.81 for Debian Linux. This will not be a linux based OS. It's also not posix, linux, unix, windows, bsd or any other derivitive thereof but does use the same concepts. The system I am developing on has a Intel i7-3770k and is an x86_64 bit and runs Debian 10 Buster Linux with Linux Kernel version 4.19.0-25-amd64 (supports UNIX 98 PTY) and Bash 5.0.3 and the drive has an ext4 partition and a tempfs partition. I have the extension ms-vscode.cpptools installed on VSCode. I also have both gcc 8.3.0 and clang 7.0.1-8+deb10u2 installed. All of my compilers, debuggers, linkers are in /usr/bin. I have Coreutils 8.30, Binutils 2.31.1, Bison 3.3.2, Diffutils 3.7, Findutils 4.6.0.225, Gawk 4.2.1, Grep 3.3, Gzip 1.9, M4 1.4.18, Make 4.2.1, Patch 2.7.6, Perl 5.28.1, Python 3.7.3, Sed 4.7, Tar 1.30, Texinfo 6.5, Xz 5.2.4. The operating system would run on any system that has a 386 CPU up to a 32 bit only Prescott Pentium 4 released in 2004. I am using gcc to compile, ld to link, gdb to debug, nasm to do the assembly and qemu to emulate the system. it has a two stage bootloader. The os should boot from floppy, hard drive and optical media.
|
||||
|
||||
here is the file structure:
|
||||
|
||||
ClassicOS/
|
||||
├── .github/
|
||||
@ -17,6 +19,7 @@ ClassicOS/
|
||||
│ │ │ └── menu.lst
|
||||
│ │ ├── boot.asm
|
||||
│ │ ├── boot.o
|
||||
│ │ ├── boot2.asm
|
||||
│ │ ├── linker.ld
|
||||
│ ├── cpu/
|
||||
│ │ ├── cpu.c
|
||||
@ -80,12 +83,20 @@ ClassicOS/
|
||||
│ │ │ │ │ ├── memory.h
|
||||
│ │ │ │ │ ├── types.h
|
||||
│ │ │ │ │ └── types.h
|
||||
│ │ │ │ └── isr/
|
||||
│ │ │ │ │ ├── exceptions.c
|
||||
│ │ │ │ │ ├── exceptions.h
|
||||
│ │ │ │ │ ├── isr.asm
|
||||
│ │ │ │ │ ├── isr.c
|
||||
│ │ │ │ │ └── isr.h
|
||||
│ │ │ │ └── memory/
|
||||
│ │ │ │ │ ├── memory.c
|
||||
│ │ │ │ │ └── memory.o
|
||||
│ │ │ ├── gdt.asm
|
||||
│ │ │ ├── gdt.c
|
||||
│ │ │ ├── gdt.h
|
||||
│ │ │ ├── gdt.o
|
||||
│ │ │ ├── idt.asm
|
||||
│ │ │ ├── idt.c
|
||||
│ │ │ ├── idt.h
|
||||
│ │ │ ├── gdt.o
|
||||
@ -101,7 +112,9 @@ ClassicOS/
|
||||
│ │ ├── kernel.o
|
||||
│ │ ├── linker.ld
|
||||
│ │ ├── print.c
|
||||
│ │ ├── print.c
|
||||
│ │ ├── print.h
|
||||
│ │ ├── stack.c
|
||||
│ │ ├── stack.h
|
||||
│ │ ├── timer.c
|
||||
│ │ └── timer.h
|
||||
│ └── shell/
|
||||
|
@ -2,86 +2,130 @@
|
||||
[ORG 0x7c00]
|
||||
|
||||
start:
|
||||
XOR AX, AX
|
||||
MOV DS, AX
|
||||
MOV SS, AX
|
||||
MOV SP, 0x7c00
|
||||
; Processor initialization (only stack segment register needed)
|
||||
mov ss, 0x1000 ; Set stack segment register
|
||||
mov sp, 0x7C00 ; Set stack pointer (SP)
|
||||
mov ds, ss ; Set data segment register (DS)
|
||||
|
||||
MOV SI, loading
|
||||
CALL printnl
|
||||
; Identify boot device using BIOS calls
|
||||
identify_drive:
|
||||
mov ah, 0x0E ; Get Interrupt Vector for INT 13h (Disk Services)
|
||||
int 0x80
|
||||
cmp cl, 0x41 ; Check for floppy drive interrupt vector (example)
|
||||
je is_floppy
|
||||
cmp cl, 0x80 ; Check for hard disk interrupt vector (example)
|
||||
je is_harddrive
|
||||
; Handle invalid drive type (error handling)
|
||||
...
|
||||
|
||||
CALL reset_drives
|
||||
CALL read_drive
|
||||
is_floppy:
|
||||
Perform floppy disk access (assuming AH=0x02 for read sectors)
|
||||
mov ah, 0x02 ; Read sectors
|
||||
mov al, 1 ; Number of sectors to read (1)
|
||||
|
||||
MOV SI, loadedSS
|
||||
CALL printnl
|
||||
; Set CH, CL, DH, DL for floppy based on your system configuration
|
||||
; (Replace these values with appropriate settings for your floppy drive)
|
||||
mov ch, 0 ; Cylinder (example, adjust based on your floppy)
|
||||
mov cl, 1 ; Sector number (example, adjust based on boot sector location)
|
||||
mov dh, 0 ; Head number (example, typically 0 for single-sided floppies)
|
||||
mov dl, 0x00 ; Drive number (0x00 for floppy drive A)
|
||||
|
||||
JMP 0x1000:0x0000
|
||||
; Set ES:BX to the memory address where you want to store the read data
|
||||
mov es, 0x1000 ; Example segment (adjust as needed)
|
||||
mov bx, 0x0 ; Memory offset within the segment (example)
|
||||
|
||||
RET
|
||||
int 0x13
|
||||
jc error_floppy
|
||||
|
||||
printnl:
|
||||
LODSB
|
||||
OR AL, AL
|
||||
JZ .stop
|
||||
; Implement error handling (omitted here for brevity)
|
||||
; Process the read data from the floppy sector (load second stage bootloader, etc.)
|
||||
|
||||
MOV AH, 0x0E
|
||||
MOV BH, 0x00
|
||||
MOV BL, 0x07
|
||||
INT 0x10
|
||||
is_harddrive:
|
||||
|
||||
JMP printnl
|
||||
; Sample code (not guaranteed to work universally)
|
||||
mov ah, 0x02 ; Set function for read sectors
|
||||
mov al, 0x01 ; Read one sector
|
||||
; Set CH, CL, DH for desired sector location (e.g., first sector)
|
||||
mov dl, 0x80 ; Drive number (assuming drive A is boot device)
|
||||
mov es, segment_address ; Set ES for buffer to store read data
|
||||
mov bx, buffer_offset ; Set BX for offset within the buffer
|
||||
|
||||
.stop:
|
||||
MOV AH, 0x03 ; AH = 0x03 (Get Cursor Position and Shape)
|
||||
XOR BH, BH ; BH = 0x00 (Video Page Number)
|
||||
INT 0x10 ; Call video interrupt
|
||||
int 13h ; Raise BIOS interrupt for disk read
|
||||
|
||||
INC DH
|
||||
; Check Carry flag for error handling
|
||||
jc harddrive_not_found ; Jump if Carry flag is set (potential error)
|
||||
|
||||
MOV AH, 0x02 ; Set cursor position
|
||||
XOR BH, BH ; Page number
|
||||
XOR DL, DL ; Column (start from 0)
|
||||
INT 0x10 ; Call video interrupt
|
||||
RET
|
||||
; Hard drive likely present (further processing can occur)
|
||||
|
||||
reset_drives:
|
||||
XOR AH, AH ; 0 = Reset floppy disk
|
||||
INT 0x13
|
||||
JC .reset_error ; If carry flag was set, try again
|
||||
RET
|
||||
; ... (rest of your bootloader code)
|
||||
|
||||
.reset_error:
|
||||
MOV SI, resetError
|
||||
CALL printnl
|
||||
RET
|
||||
harddrive_not_found:
|
||||
; Handle error condition (missing drive or other issue)
|
||||
|
||||
read_drive:
|
||||
MOV AH, 0x02
|
||||
MOV AL, 1 ; Number of sectors to read
|
||||
XOR CH, CH ; Cylinder/Track number
|
||||
MOV CL, 2 ; Sector number (starting from 1)
|
||||
XOR DH, DH ; Head number
|
||||
XOR DL, DL ; Drive number (0x0 for floppy disk / 0x80 for hard disk)
|
||||
; ... (error handling logic)
|
||||
|
||||
MOV BX, 0x1000
|
||||
MOV ES, BX
|
||||
XOR BX, BX
|
||||
memory_error:
|
||||
; ... (error handling or continue with limited memory)
|
||||
|
||||
INT 0x13
|
||||
; Second stage loading (simplified example)
|
||||
Here's an improved version of the load_second_stage section with the placeholder jump replaced by actual loading logic:
|
||||
Code snippet
|
||||
|
||||
JC .read_error
|
||||
RET
|
||||
load_second_stage:
|
||||
; Calculate address of second stage bootloader (assuming offset from boot sector)
|
||||
mov dx, 0x0000 ; Clear DX register for better calculation
|
||||
add dx, sector_count ; Add number of sectors to skip (adjust as needed)
|
||||
shl dx, 5 ; Multiply by sector size (512 bytes)
|
||||
add dx, 0x7C00 ; Add boot sector address offset
|
||||
|
||||
.read_error:
|
||||
MOV SI, readError
|
||||
CALL printnl
|
||||
RET
|
||||
; Read second stage bootloader from calculated address
|
||||
mov ah, 0x02 ; Function for reading sectors
|
||||
mov al, 1 ; Number of sectors to read (1 for second stage)
|
||||
mov es, dx ; Set ES segment register to calculated address
|
||||
mov bx, 0x0000 ; Set BX offset within the segment (example)
|
||||
|
||||
loading db "Loading Second Stage", 0
|
||||
resetError db "Failed to reset drives.", 0
|
||||
readError db "Failed to read drive", 0
|
||||
loadedSS db "Loaded second stage...", 0
|
||||
int 13h ; Raise BIOS interrupt for disk read
|
||||
|
||||
; Check Carry flag for error handling
|
||||
jc memory_error ; Jump if Carry flag is set (potential error)
|
||||
|
||||
; Second stage likely loaded successfully, jump to it
|
||||
jmp second_stage_address ; Direct jump to the defined address
|
||||
|
||||
error_floppy:
|
||||
; Display a basic error message (optional)
|
||||
mov ah, 0x0E ; BIOS video call for displaying text (educational purposes)
|
||||
mov bh, 0x00 ; Set background color (black)
|
||||
mov bl, 0x07 ; Set text color (white)
|
||||
mov dx, error_floppy_message ; Address of error message string
|
||||
int 0x10 ; BIOS video interrupt
|
||||
|
||||
; Halt the boot process (replace with a retry or more advanced error handling)
|
||||
hlt ; Halt instruction
|
||||
|
||||
error_floppy_message db 'Floppy disk read error!', 0x0
|
||||
|
||||
memory_error:
|
||||
; Check for available memory (replace with actual method)
|
||||
; ... (e.g., call BIOS service for memory size or use a constant value)
|
||||
cmp available_memory, memory_threshold ; Compare with minimum required memory
|
||||
jb limited_memory_boot ; Jump if below threshold
|
||||
|
||||
; ... (standard error handling for other scenarios)
|
||||
|
||||
limited_memory_boot:
|
||||
; Perform minimal setup for limited memory boot
|
||||
; ... (disable non-essential features, adjust kernel parameters)
|
||||
|
||||
; Load and jump to second stage bootloader (potentially with adjustments)
|
||||
; ... (modify loading logic if necessary)
|
||||
|
||||
; Define variables used for calculation (adjust as needed)
|
||||
sector_count db 1 ; Number of sectors to skip before second stage (change if needed)
|
||||
second_stage_address equ 0x8000 ; Replace with actual address of your second stage bootloader
|
||||
available_memory equ 0x100000 ; Replace with actual memory size detection (1MB in this example)
|
||||
memory_threshold equ 0x0A0000 ; Example minimum memory required (adjust based on needs)
|
||||
|
||||
; Padding and magic number (standard practice)
|
||||
times 510-($-$$) db 0
|
||||
dw 0xaa55
|
||||
dw 0xaa55
|
||||
|
@ -1,32 +1,112 @@
|
||||
#include "vga.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define VGA_MEMORY_ADDRESS 0xA0000
|
||||
#define VGA_MEMORY_SIZE 0x60000
|
||||
|
||||
static uint8_t* vga_memory = (uint8_t*) VGA_MEMORY_ADDRESS;
|
||||
static uint16_t vga_width = VGA_WIDTH;
|
||||
static uint16_t vga_height = VGA_HEIGHT;
|
||||
static uint8_t vga_depth = VGA_DEPTH;
|
||||
|
||||
void vga_init() {
|
||||
// Initialize VGA driver here
|
||||
}
|
||||
|
||||
void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth) {
|
||||
// Set VGA resolution here
|
||||
}
|
||||
|
||||
void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color) {
|
||||
// Draw a pixel on the screen at (x, y) with the given color
|
||||
uint32_t offset = y * vga_width + x;
|
||||
vga_memory[offset] = color;
|
||||
}
|
||||
|
||||
void vga_clear_screen(uint8_t color) {
|
||||
// Clear the screen with the given color
|
||||
for (uint32_t i = 0; i < vga_width * vga_height; i++) {
|
||||
vga_memory[i] = color;
|
||||
}
|
||||
}
|
||||
#include "vga.h"
|
||||
#include <memory.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
uint8_t *map_memory(uint32_t base_address, uint32_t size);
|
||||
|
||||
#define VGA_MEMORY_ADDRESS 0xA0000
|
||||
#define VGA_MEMORY_SIZE 0x60000
|
||||
#define VGA_MEMORY_BASE_ADDRESS 0xA0000
|
||||
|
||||
#define COLOR_GREEN 0x00FF00
|
||||
|
||||
uint8_t *vga_memory = (uint8_t *)VGA_MEMORY_ADDRESS;
|
||||
static uint16_t vga_width = VGA_WIDTH;
|
||||
static uint16_t vga_height = VGA_HEIGHT;
|
||||
static uint8_t vga_depth = VGA_DEPTH;
|
||||
uint8_t *framebuffer = (uint8_t *)vga_memory;
|
||||
|
||||
// Set a specific pixel color (assuming RGB format)
|
||||
int x = 10;
|
||||
int y = 20;
|
||||
int color = 0x00FF00; // Green
|
||||
|
||||
framebuffer[y * width + x * 3] = (color & 0x00FF) >> 8; // Green value
|
||||
framebuffer[y * width + x * 3 + 1] = color & 0x00FF; // Blue value
|
||||
framebuffer[y * width + x * 3 + 2] = color >> 8; // Red value
|
||||
|
||||
uint8_t misc_output_value = read_vga_register(0x3C2);
|
||||
|
||||
// Check bit 1 to determine text mode (0) or graphics mode (1)
|
||||
if (misc_output_value & 0x02)
|
||||
{
|
||||
printf("Graphics mode active\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Text mode active\n");
|
||||
}
|
||||
|
||||
// Function to retrieve the actual VGA base memory address (if needed)
|
||||
uint32_t get_vga_memory_address()
|
||||
{
|
||||
// Implement logic to query the system for the actual VGA base address
|
||||
// This might involve consulting BIOS information, system calls, etc.
|
||||
// Return the retrieved address if successful, otherwise return the default value.
|
||||
return VGA_MEMORY_ADDRESS;
|
||||
}
|
||||
|
||||
void vga_init(void)
|
||||
{
|
||||
// Initialize VGA driver here
|
||||
vga_memory = (uint8_t *)map_memory(VGA_MEMORY_BASE_ADDRESS, VGA_MEMORY_SIZE);
|
||||
|
||||
if (vga_memory == NULL)
|
||||
{
|
||||
// Handle memory mapping error
|
||||
fprintf(stderr, "Failed to map VGA Memory\n");
|
||||
}
|
||||
|
||||
framebuffer = vga_memory;
|
||||
}
|
||||
|
||||
// Replace with actual functions to read VGA registers based on your system
|
||||
uint8_t read_vga_register(uint16_t register_address)
|
||||
{
|
||||
uint8_t value = inb(register_address); // Read from the specified port
|
||||
return value;
|
||||
}
|
||||
|
||||
int inb(uint16_t port) {
|
||||
// Implement port access logic (replace with system-specific function)
|
||||
}
|
||||
|
||||
void outb(uint16_t port, uint8_t data) {
|
||||
|
||||
}
|
||||
|
||||
void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth)
|
||||
{
|
||||
// Set VGA resolution here
|
||||
// Example (replace with actual register values and writes based on your system):
|
||||
|
||||
// Sequencer unlock
|
||||
outb(0x3C4, 0x01);
|
||||
outb(0x3C5, 0x01);
|
||||
|
||||
// Set specific CRTC registers for desired resolution and refresh rate
|
||||
// ... (write to specific VGA registers using outb)
|
||||
|
||||
// Graphics controller registers for memory access
|
||||
// ... (write to specific VGA registers using outb)
|
||||
}
|
||||
|
||||
void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color)
|
||||
{
|
||||
// Draw a pixel on the screen at (x, y) with the given color
|
||||
uint32_t offset = y * vga_width + x;
|
||||
vga_memory[offset] = color;
|
||||
}
|
||||
|
||||
void vga_clear_screen(uint8_t color)
|
||||
{
|
||||
// Clear the screen with the given color
|
||||
for (uint32_t i = 0; i < vga_width * vga_height; i++)
|
||||
{
|
||||
vga_memory[i] = color;
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,22 @@
|
||||
#ifndef VGA_H
|
||||
#define VGA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define VGA_WIDTH 640
|
||||
#define VGA_HEIGHT 480
|
||||
#define VGA_DEPTH 8
|
||||
|
||||
void vga_init();
|
||||
void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth);
|
||||
void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color);
|
||||
void vga_clear_screen(uint8_t color);
|
||||
|
||||
#endif
|
||||
#ifndef VGA_H
|
||||
#define VGA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t depth;
|
||||
// Add other relevant settings like color palette, etc.
|
||||
} vga_display_settings_t;
|
||||
|
||||
void vga_init();
|
||||
void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth);
|
||||
void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color);
|
||||
void vga_clear_screen(uint8_t color);
|
||||
|
||||
uint8_t read_vga_register(uint16_t register_address);
|
||||
int inb(uint16_t port);
|
||||
void outb(uint16_t port, uint8_t data);
|
||||
|
||||
#endif
|
||||
|
@ -1,66 +1,102 @@
|
||||
#include "keyboard.h"
|
||||
#include "../io/io.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Keyboard input buffer
|
||||
#define KEYBOARD_BUFFER_SIZE 32
|
||||
#define KEYBOARD_DATA_PORT 0x60
|
||||
#define KEYBOARD_INTERRUPT_VECTOR 0x09
|
||||
#define KEYBOARD_COMMAND_PORT 0x64
|
||||
#define KEYBOARD_DATA_PORT 0x60
|
||||
#define KEYBOARD_ENABLE_COMMAND 0xAE
|
||||
#define KEYBOARD_ENABLE_SCANCODE 0xF4
|
||||
#define KEYBOARD_ACKNOWLEDGE_SCANCODE 0xFA
|
||||
|
||||
static uint8_t keyboard_buffer[KEYBOARD_BUFFER_SIZE];
|
||||
static size_t keyboard_buffer_head = 0;
|
||||
static size_t keyboard_buffer_tail = 0;
|
||||
|
||||
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
||||
void enable_interrupt(uint8_t vector);
|
||||
|
||||
void KeyboardInterruptHandler()
|
||||
{
|
||||
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
|
||||
|
||||
// Add scancode to buffer
|
||||
keyboard_buffer[keyboard_buffer_head] = scancode;
|
||||
keyboard_buffer_head = (keyboard_buffer_head + 1) % KEYBOARD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
// Initialize keyboard
|
||||
void keyboard_init()
|
||||
{
|
||||
// Install keyboard interrupt handler
|
||||
//set_interrupt_vector(KEYBOARD_INTERRUPT_VECTOR, KeyboardInterruptHandler);
|
||||
//enable_interrupt(KEYBOARD_INTERRUPT_VECTOR);
|
||||
|
||||
// Enable keyboard
|
||||
outb(KEYBOARD_COMMAND_PORT, KEYBOARD_ENABLE_COMMAND);
|
||||
while (inb(KEYBOARD_COMMAND_PORT) & 0x02)
|
||||
;
|
||||
outb(KEYBOARD_DATA_PORT, KEYBOARD_ENABLE_SCANCODE);
|
||||
while (inb(KEYBOARD_DATA_PORT) != KEYBOARD_ACKNOWLEDGE_SCANCODE)
|
||||
;
|
||||
}
|
||||
|
||||
// Check if keyboard buffer is empty
|
||||
bool keyboard_buffer_empty()
|
||||
{
|
||||
return keyboard_buffer_head == keyboard_buffer_tail;
|
||||
}
|
||||
|
||||
// Read scancode from keyboard buffer
|
||||
uint8_t keyboard_read_scancode()
|
||||
{
|
||||
if (keyboard_buffer_empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t scancode = keyboard_buffer[keyboard_buffer_tail];
|
||||
keyboard_buffer_tail = (keyboard_buffer_tail + 1) % KEYBOARD_BUFFER_SIZE;
|
||||
return scancode;
|
||||
}
|
||||
#include "keyboard.h"
|
||||
#include "../io/io.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Keyboard input buffer
|
||||
#define KEYBOARD_BUFFER_SIZE 32
|
||||
#define KEYBOARD_DATA_PORT 0x60
|
||||
#define KEYBOARD_INTERRUPT_VECTOR 0x09
|
||||
#define KEYBOARD_COMMAND_PORT 0x64
|
||||
#define KEYBOARD_DATA_PORT 0x60
|
||||
#define KEYBOARD_ENABLE_COMMAND 0xAE
|
||||
#define KEYBOARD_ENABLE_SCANCODE 0xF4
|
||||
#define KEYBOARD_ACKNOWLEDGE_SCANCODE 0xFA
|
||||
#define KEYCODE_UNKNOWN 0xFF
|
||||
#define KEYCODE_C 0x03
|
||||
|
||||
static uint8_t keyboard_buffer[KEYBOARD_BUFFER_SIZE];
|
||||
static size_t keyboard_buffer_head = 0;
|
||||
static size_t keyboard_buffer_tail = 0;
|
||||
|
||||
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
||||
void enable_interrupt(uint8_t vector);
|
||||
|
||||
void KeyboardInterruptHandler()
|
||||
{
|
||||
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
|
||||
uint8_t keycode = translate_scancode_to_keycode(scancode);
|
||||
|
||||
// Add scancode to buffer
|
||||
keyboard_buffer[keyboard_buffer_head] = scancode;
|
||||
keyboard_buffer_head = (keyboard_buffer_head + 1) % KEYBOARD_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
uint8_t translate_scancode_to_keycode(uint8_t scancode)
|
||||
{
|
||||
static uint8_t keycode_map[128] = {
|
||||
[0x01] = KEYCODE_ESC,
|
||||
[0x02] = KEYCODE_1,
|
||||
[0x03] = KEYCODE_2,
|
||||
[0x04] = KEYCODE_3,
|
||||
[0x05] = KEYCODE_4,
|
||||
[0x06] = KEYCODE_5,
|
||||
[0x07] = KEYCODE_6,
|
||||
[0x08] = KEYCODE_7,
|
||||
[0x09] = KEYCODE_8,
|
||||
[0x0A] = KEYCODE_9,
|
||||
[0x0B] = KEYCODE_0,
|
||||
[0x0C] = KEYCODE_MINUS,
|
||||
[0x0D] = KEYCODE_EQUALS,
|
||||
[0x0E] = KEYCODE_BACKSPACE,
|
||||
// ... (complete the rest based on the scancode table)
|
||||
[0xE0] = 0, // Handle extended scancodes (e.g., Print Screen) separately
|
||||
};
|
||||
|
||||
if (scancode < sizeof(keycode_map))
|
||||
{
|
||||
// Map scancode directly to keycode
|
||||
return keycode_map[scancode];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle unknown scancode
|
||||
return KEYCODE_UNKNOWN; // Or return a special keycode indicating error
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize keyboard
|
||||
void keyboard_init()
|
||||
{
|
||||
// Install keyboard interrupt handler
|
||||
set_interrupt_vector(KEYBOARD_INTERRUPT_VECTOR, KeyboardInterruptHandler);
|
||||
enable_interrupt(KEYBOARD_INTERRUPT_VECTOR);
|
||||
|
||||
// Enable keyboard
|
||||
outb(KEYBOARD_COMMAND_PORT, KEYBOARD_ENABLE_COMMAND);
|
||||
while (inb(KEYBOARD_COMMAND_PORT) & 0x02)
|
||||
;
|
||||
outb(KEYBOARD_DATA_PORT, KEYBOARD_ENABLE_SCANCODE);
|
||||
while (inb(KEYBOARD_DATA_PORT) != KEYBOARD_ACKNOWLEDGE_SCANCODE)
|
||||
;
|
||||
}
|
||||
|
||||
// Check if keyboard buffer is empty
|
||||
bool keyboard_buffer_empty()
|
||||
{
|
||||
return keyboard_buffer_head == keyboard_buffer_tail;
|
||||
}
|
||||
|
||||
// Read scancode from keyboard buffer
|
||||
uint8_t keyboard_read_scancode()
|
||||
{
|
||||
if (keyboard_buffer_empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t scancode = keyboard_buffer[keyboard_buffer_tail];
|
||||
keyboard_buffer_tail = (keyboard_buffer_tail + 1) % KEYBOARD_BUFFER_SIZE;
|
||||
return scancode;
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
#ifndef KEYBOARD_H
|
||||
#define KEYBOARD_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void KeyboardInterruptHandler();
|
||||
|
||||
void keyboard_init();
|
||||
bool keyboard_buffer_empty();
|
||||
uint8_t keyboard_read_scancode();
|
||||
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
||||
void enable_interrupt(uint8_t vector);
|
||||
|
||||
#endif
|
||||
#ifndef KEYBOARD_H
|
||||
#define KEYBOARD_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void KeyboardInterruptHandler();
|
||||
|
||||
void keyboard_init();
|
||||
bool keyboard_buffer_empty();
|
||||
uint8_t keyboard_read_scancode();
|
||||
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
||||
void enable_interrupt(uint8_t vector);
|
||||
uint8_t translate_scancode_to_keycode(uint8_t scancode);
|
||||
#endif
|
||||
|
@ -1,98 +1,98 @@
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "isr/isr.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#define BYTE_MASK 0xFF
|
||||
#define PAGE_FAULT 14
|
||||
#define DOUBLE_FAULT 8
|
||||
#define SYSTEM_CALL 80
|
||||
#define TIMER 20
|
||||
|
||||
#define ISR_TABLE_SIZE 256
|
||||
|
||||
// GDT table
|
||||
struct gdt_entry *gdt;
|
||||
|
||||
// GDT constants
|
||||
enum GDT_ACCESS
|
||||
{
|
||||
GDT_ACCESS_PRESENT = 0x80
|
||||
};
|
||||
|
||||
// GDT base and limit constants
|
||||
enum GDT_BASE_LIMIT
|
||||
{
|
||||
GDT_BASE_MIDDLE_SHIFT = 16,
|
||||
GDT_BASE_HIGH_SHIFT = 24,
|
||||
GDT_GRANULARITY_SHIFT = 16,
|
||||
GDT_GRANULARITY_MASK = 0x0F,
|
||||
GDT_ACCESS_MASK = 0xF0,
|
||||
GDT_LIMIT_MASK = 0xFFFF
|
||||
};
|
||||
|
||||
extern void LoadGDT(struct gdt_ptr* gdt);
|
||||
|
||||
// Initialize a GDT entry
|
||||
void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access,
|
||||
uint8_t gran, struct gdt_entry *const gdt)
|
||||
{
|
||||
gdt[num].base_low = (base & GDT_LIMIT_MASK);
|
||||
gdt[num].base_middle = (base >> GDT_BASE_MIDDLE_SHIFT) & BYTE_MASK;
|
||||
gdt[num].base_high = (base >> GDT_BASE_HIGH_SHIFT) & BYTE_MASK;
|
||||
gdt[num].limit_low = (limit & GDT_LIMIT_MASK);
|
||||
gdt[num].granularity =
|
||||
(limit >> GDT_GRANULARITY_SHIFT) & GDT_GRANULARITY_MASK;
|
||||
gdt[num].granularity |= gran & GDT_ACCESS_MASK;
|
||||
gdt[num].access = access;
|
||||
}
|
||||
|
||||
void gdt_init()
|
||||
{
|
||||
// Set up GDT pointer
|
||||
struct gdt_ptr gp;
|
||||
gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
|
||||
//gdt = (struct gdt_entry *)malloc(sizeof(struct gdt_entry) * 3);
|
||||
//memset(gdt, 0, sizeof(struct gdt_entry) * 3);
|
||||
|
||||
// Initialize GDT entries
|
||||
gdt_set_gate(0, 0, 0, 0, 0, gdt); // Null segment
|
||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF, gdt); // Code segment
|
||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF, gdt); // Data segment
|
||||
|
||||
// Load GDT
|
||||
struct gdt_ptr gdtp;
|
||||
gdtp.limit = gp.limit;
|
||||
gdtp.base = (uintptr_t)gdt;
|
||||
|
||||
LoadGDT(&gdtp);
|
||||
|
||||
/*
|
||||
__asm__ volatile("mov $0x10, %ax\n\t"
|
||||
"mov %ax, %ds\n\t"
|
||||
"mov %ax, %es\n\t"
|
||||
"mov %ax, %fs\n\t"
|
||||
"mov %ax, %gs\n\t"
|
||||
"ljmp $0x08, $next_label\n\t"
|
||||
"next_label:");
|
||||
*/
|
||||
}
|
||||
|
||||
// Exception handlers
|
||||
extern void divide_error(struct idt_regs *regs);
|
||||
extern void page_fault(struct idt_regs *regs);
|
||||
extern void general_protection_fault();
|
||||
extern void double_fault();
|
||||
|
||||
// Interrupt handlers
|
||||
extern void system_call();
|
||||
extern void timer();
|
||||
extern void keyboard();
|
||||
extern void device();
|
||||
#include "gdt.h"
|
||||
#include "idt.h"
|
||||
#include "isr/isr.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#define BYTE_MASK 0xFF
|
||||
#define PAGE_FAULT 14
|
||||
#define DOUBLE_FAULT 8
|
||||
#define SYSTEM_CALL 80
|
||||
#define TIMER 20
|
||||
|
||||
#define ISR_TABLE_SIZE 256
|
||||
|
||||
// GDT table
|
||||
struct gdt_entry gdt_entries[3] __attribute__((aligned(0x1000)));
|
||||
|
||||
// GDT constants
|
||||
enum GDT_ACCESS
|
||||
{
|
||||
GDT_ACCESS_PRESENT = 0x80
|
||||
};
|
||||
|
||||
// GDT base and limit constants
|
||||
enum GDT_BASE_LIMIT
|
||||
{
|
||||
GDT_BASE_MIDDLE_SHIFT = 16,
|
||||
GDT_BASE_HIGH_SHIFT = 24,
|
||||
GDT_GRANULARITY_SHIFT = 16,
|
||||
GDT_GRANULARITY_MASK = 0x0F,
|
||||
GDT_ACCESS_MASK = 0xF0,
|
||||
GDT_LIMIT_MASK = 0xFFFF
|
||||
};
|
||||
|
||||
extern void LoadGDT(struct gdt_ptr* gdt);
|
||||
|
||||
// Initialize a GDT entry
|
||||
void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access,
|
||||
uint8_t gran, struct gdt_entry *const gdt)
|
||||
{
|
||||
gdt[num].base_low = (base & GDT_LIMIT_MASK);
|
||||
gdt[num].base_middle = (base >> GDT_BASE_MIDDLE_SHIFT) & BYTE_MASK;
|
||||
gdt[num].base_high = (base >> GDT_BASE_HIGH_SHIFT) & BYTE_MASK;
|
||||
gdt[num].limit_low = (limit & GDT_LIMIT_MASK);
|
||||
gdt[num].granularity =
|
||||
(limit >> GDT_GRANULARITY_SHIFT) & GDT_GRANULARITY_MASK;
|
||||
gdt[num].granularity |= gran & GDT_ACCESS_MASK;
|
||||
gdt[num].access = access;
|
||||
}
|
||||
|
||||
void gdt_init()
|
||||
{
|
||||
// Set up GDT pointer
|
||||
struct gdt_ptr gp;
|
||||
gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
|
||||
//gdt = (struct gdt_entry *)malloc(sizeof(struct gdt_entry) * 3);
|
||||
//memset(gdt, 0, sizeof(struct gdt_entry) * 3);
|
||||
|
||||
// Initialize GDT entries
|
||||
gdt_set_gate(0, 0, 0, 0, 0, &gdt_entries[0]); // Null segment
|
||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF, &gdt_entries[1]); // Code segment
|
||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF, &gdt_entries[2]); // Data segment
|
||||
|
||||
// Load GDT
|
||||
struct gdt_ptr gdtp;
|
||||
gdtp.limit = gp.limit;
|
||||
gdtp.base = (uintptr_t)gdt;
|
||||
|
||||
LoadGDT(&gdtp);
|
||||
|
||||
/*
|
||||
__asm__ volatile("mov $0x10, %ax\n\t"
|
||||
"mov %ax, %ds\n\t"
|
||||
"mov %ax, %es\n\t"
|
||||
"mov %ax, %fs\n\t"
|
||||
"mov %ax, %gs\n\t"
|
||||
"ljmp $0x08, $next_label\n\t"
|
||||
"next_label:");
|
||||
*/
|
||||
}
|
||||
|
||||
// Exception handlers
|
||||
extern void divide_error(struct idt_regs *regs);
|
||||
extern void page_fault(struct idt_regs *regs);
|
||||
extern void general_protection_fault();
|
||||
extern void double_fault();
|
||||
|
||||
// Interrupt handlers
|
||||
extern void system_call();
|
||||
extern void timer();
|
||||
extern void keyboard();
|
||||
extern void device();
|
||||
|
@ -2,5 +2,6 @@ global LoadIDT
|
||||
|
||||
section .text
|
||||
LoadIDT:
|
||||
LIDT [ESP + 32]
|
||||
mov eax, [offset idt] ; Get the IDT address
|
||||
LIDT [eax + 8*0x33] ; Load only the timer interrupt entry (offset 8*0x33)
|
||||
RET
|
@ -1,19 +1,32 @@
|
||||
#include "idt.h"
|
||||
#include "isr/isr.h"
|
||||
#include "../../../drivers/keyboard/keyboard.h"
|
||||
|
||||
struct idt_entry idt[256];
|
||||
|
||||
extern void LoadIDT(struct idt_entry* entry);
|
||||
|
||||
// Initialize the IDT
|
||||
void InitializeIDT()
|
||||
{
|
||||
idt[KEYBOARD_INTERRUPT].base_lo = ((uint16_t*)KeyboardInterruptHandler)[0];
|
||||
idt[KEYBOARD_INTERRUPT].sel = 0x08;
|
||||
idt[KEYBOARD_INTERRUPT].always0 = 0x00;
|
||||
idt[KEYBOARD_INTERRUPT].flags = 0x8E;
|
||||
idt[KEYBOARD_INTERRUPT].base_hi = ((uint16_t*)KeyboardInterruptHandler)[1];
|
||||
|
||||
LoadIDT(&idt[KEYBOARD_INTERRUPT]);
|
||||
}
|
||||
#include "idt.h"
|
||||
#include "../../../drivers/keyboard/keyboard.h"
|
||||
#include "isr/isr.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct idt_entry idt[256];
|
||||
|
||||
extern void LoadIDT(struct idt_entry *entry);
|
||||
|
||||
void TimerInterruptHandler()
|
||||
{
|
||||
static uint16_t timer_count = 0;
|
||||
timer_count++;
|
||||
}
|
||||
|
||||
// Initialize the IDT
|
||||
void InitializeIDT()
|
||||
{
|
||||
idt[KEYBOARD_INTERRUPT].base_lo = ((uint16_t *)KeyboardInterruptHandler)[0];
|
||||
idt[KEYBOARD_INTERRUPT].sel = 0x08;
|
||||
idt[KEYBOARD_INTERRUPT].always0 = 0x00;
|
||||
idt[KEYBOARD_INTERRUPT].flags = 0x8E;
|
||||
idt[KEYBOARD_INTERRUPT].base_hi = ((uint16_t *)KeyboardInterruptHandler)[1];
|
||||
|
||||
idt[0x33].base_lo = (uint16_t)TimerInterruptHandler;
|
||||
idt[0x33].sel = 0x08;
|
||||
idt[0x33].always0 = 0x00;
|
||||
idt[0x33].flags = 0x8E;
|
||||
idt[0x33].base_hi = (uint16_t)TimerInterruptHandler >> 16;
|
||||
|
||||
LoadIDT(&idt[0]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user