mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2024-11-24 06:46:53 -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",
|
"*.json": "default",
|
||||||
"*.asm": "default"
|
"*.asm": "default"
|
||||||
},
|
},
|
||||||
"C_Cpp.default.intelliSenseMode": "linux-clang-x86",
|
"C_Cpp.default.intelliSenseMode": "linux-gcc-x86",
|
||||||
"cmake.cmakePath": "/usr/bin/cmake"
|
"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/
|
ClassicOS/
|
||||||
├── .github/
|
├── .github/
|
||||||
@ -17,6 +19,7 @@ ClassicOS/
|
|||||||
│ │ │ └── menu.lst
|
│ │ │ └── menu.lst
|
||||||
│ │ ├── boot.asm
|
│ │ ├── boot.asm
|
||||||
│ │ ├── boot.o
|
│ │ ├── boot.o
|
||||||
|
│ │ ├── boot2.asm
|
||||||
│ │ ├── linker.ld
|
│ │ ├── linker.ld
|
||||||
│ ├── cpu/
|
│ ├── cpu/
|
||||||
│ │ ├── cpu.c
|
│ │ ├── cpu.c
|
||||||
@ -80,12 +83,20 @@ ClassicOS/
|
|||||||
│ │ │ │ │ ├── memory.h
|
│ │ │ │ │ ├── memory.h
|
||||||
│ │ │ │ │ ├── types.h
|
│ │ │ │ │ ├── types.h
|
||||||
│ │ │ │ │ └── types.h
|
│ │ │ │ │ └── types.h
|
||||||
|
│ │ │ │ └── isr/
|
||||||
|
│ │ │ │ │ ├── exceptions.c
|
||||||
|
│ │ │ │ │ ├── exceptions.h
|
||||||
|
│ │ │ │ │ ├── isr.asm
|
||||||
|
│ │ │ │ │ ├── isr.c
|
||||||
|
│ │ │ │ │ └── isr.h
|
||||||
│ │ │ │ └── memory/
|
│ │ │ │ └── memory/
|
||||||
│ │ │ │ │ ├── memory.c
|
│ │ │ │ │ ├── memory.c
|
||||||
│ │ │ │ │ └── memory.o
|
│ │ │ │ │ └── memory.o
|
||||||
|
│ │ │ ├── gdt.asm
|
||||||
│ │ │ ├── gdt.c
|
│ │ │ ├── gdt.c
|
||||||
│ │ │ ├── gdt.h
|
│ │ │ ├── gdt.h
|
||||||
│ │ │ ├── gdt.o
|
│ │ │ ├── gdt.o
|
||||||
|
│ │ │ ├── idt.asm
|
||||||
│ │ │ ├── idt.c
|
│ │ │ ├── idt.c
|
||||||
│ │ │ ├── idt.h
|
│ │ │ ├── idt.h
|
||||||
│ │ │ ├── gdt.o
|
│ │ │ ├── gdt.o
|
||||||
@ -101,7 +112,9 @@ ClassicOS/
|
|||||||
│ │ ├── kernel.o
|
│ │ ├── kernel.o
|
||||||
│ │ ├── linker.ld
|
│ │ ├── linker.ld
|
||||||
│ │ ├── print.c
|
│ │ ├── print.c
|
||||||
│ │ ├── print.c
|
│ │ ├── print.h
|
||||||
|
│ │ ├── stack.c
|
||||||
|
│ │ ├── stack.h
|
||||||
│ │ ├── timer.c
|
│ │ ├── timer.c
|
||||||
│ │ └── timer.h
|
│ │ └── timer.h
|
||||||
│ └── shell/
|
│ └── shell/
|
||||||
|
@ -2,86 +2,130 @@
|
|||||||
[ORG 0x7c00]
|
[ORG 0x7c00]
|
||||||
|
|
||||||
start:
|
start:
|
||||||
XOR AX, AX
|
; Processor initialization (only stack segment register needed)
|
||||||
MOV DS, AX
|
mov ss, 0x1000 ; Set stack segment register
|
||||||
MOV SS, AX
|
mov sp, 0x7C00 ; Set stack pointer (SP)
|
||||||
MOV SP, 0x7c00
|
mov ds, ss ; Set data segment register (DS)
|
||||||
|
|
||||||
MOV SI, loading
|
; Identify boot device using BIOS calls
|
||||||
CALL printnl
|
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
|
is_floppy:
|
||||||
CALL read_drive
|
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
|
; Set CH, CL, DH, DL for floppy based on your system configuration
|
||||||
CALL printnl
|
; (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:
|
; Implement error handling (omitted here for brevity)
|
||||||
LODSB
|
; Process the read data from the floppy sector (load second stage bootloader, etc.)
|
||||||
OR AL, AL
|
|
||||||
JZ .stop
|
|
||||||
|
|
||||||
MOV AH, 0x0E
|
is_harddrive:
|
||||||
MOV BH, 0x00
|
|
||||||
MOV BL, 0x07
|
|
||||||
INT 0x10
|
|
||||||
|
|
||||||
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:
|
int 13h ; Raise BIOS interrupt for disk read
|
||||||
MOV AH, 0x03 ; AH = 0x03 (Get Cursor Position and Shape)
|
|
||||||
XOR BH, BH ; BH = 0x00 (Video Page Number)
|
|
||||||
INT 0x10 ; Call video interrupt
|
|
||||||
|
|
||||||
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
|
; Hard drive likely present (further processing can occur)
|
||||||
XOR BH, BH ; Page number
|
|
||||||
XOR DL, DL ; Column (start from 0)
|
|
||||||
INT 0x10 ; Call video interrupt
|
|
||||||
RET
|
|
||||||
|
|
||||||
reset_drives:
|
; ... (rest of your bootloader code)
|
||||||
XOR AH, AH ; 0 = Reset floppy disk
|
|
||||||
INT 0x13
|
|
||||||
JC .reset_error ; If carry flag was set, try again
|
|
||||||
RET
|
|
||||||
|
|
||||||
.reset_error:
|
harddrive_not_found:
|
||||||
MOV SI, resetError
|
; Handle error condition (missing drive or other issue)
|
||||||
CALL printnl
|
|
||||||
RET
|
|
||||||
|
|
||||||
read_drive:
|
; ... (error handling logic)
|
||||||
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)
|
|
||||||
|
|
||||||
MOV BX, 0x1000
|
memory_error:
|
||||||
MOV ES, BX
|
; ... (error handling or continue with limited memory)
|
||||||
XOR BX, BX
|
|
||||||
|
|
||||||
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
|
load_second_stage:
|
||||||
RET
|
; 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:
|
; Read second stage bootloader from calculated address
|
||||||
MOV SI, readError
|
mov ah, 0x02 ; Function for reading sectors
|
||||||
CALL printnl
|
mov al, 1 ; Number of sectors to read (1 for second stage)
|
||||||
RET
|
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
|
int 13h ; Raise BIOS interrupt for disk read
|
||||||
resetError db "Failed to reset drives.", 0
|
|
||||||
readError db "Failed to read drive", 0
|
|
||||||
loadedSS db "Loaded second stage...", 0
|
|
||||||
|
|
||||||
|
; 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
|
times 510-($-$$) db 0
|
||||||
dw 0xaa55
|
dw 0xaa55
|
||||||
|
@ -1,32 +1,112 @@
|
|||||||
#include "vga.h"
|
#include "vga.h"
|
||||||
#include <stddef.h>
|
#include <memory.h>
|
||||||
#include <stdint.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#define VGA_MEMORY_ADDRESS 0xA0000
|
#include <stdio.h>
|
||||||
#define VGA_MEMORY_SIZE 0x60000
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
static uint8_t* vga_memory = (uint8_t*) VGA_MEMORY_ADDRESS;
|
|
||||||
static uint16_t vga_width = VGA_WIDTH;
|
uint8_t *map_memory(uint32_t base_address, uint32_t size);
|
||||||
static uint16_t vga_height = VGA_HEIGHT;
|
|
||||||
static uint8_t vga_depth = VGA_DEPTH;
|
#define VGA_MEMORY_ADDRESS 0xA0000
|
||||||
|
#define VGA_MEMORY_SIZE 0x60000
|
||||||
void vga_init() {
|
#define VGA_MEMORY_BASE_ADDRESS 0xA0000
|
||||||
// Initialize VGA driver here
|
|
||||||
}
|
#define COLOR_GREEN 0x00FF00
|
||||||
|
|
||||||
void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth) {
|
uint8_t *vga_memory = (uint8_t *)VGA_MEMORY_ADDRESS;
|
||||||
// Set VGA resolution here
|
static uint16_t vga_width = VGA_WIDTH;
|
||||||
}
|
static uint16_t vga_height = VGA_HEIGHT;
|
||||||
|
static uint8_t vga_depth = VGA_DEPTH;
|
||||||
void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color) {
|
uint8_t *framebuffer = (uint8_t *)vga_memory;
|
||||||
// Draw a pixel on the screen at (x, y) with the given color
|
|
||||||
uint32_t offset = y * vga_width + x;
|
// Set a specific pixel color (assuming RGB format)
|
||||||
vga_memory[offset] = color;
|
int x = 10;
|
||||||
}
|
int y = 20;
|
||||||
|
int color = 0x00FF00; // Green
|
||||||
void vga_clear_screen(uint8_t color) {
|
|
||||||
// Clear the screen with the given color
|
framebuffer[y * width + x * 3] = (color & 0x00FF) >> 8; // Green value
|
||||||
for (uint32_t i = 0; i < vga_width * vga_height; i++) {
|
framebuffer[y * width + x * 3 + 1] = color & 0x00FF; // Blue value
|
||||||
vga_memory[i] = color;
|
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
|
#ifndef VGA_H
|
||||||
#define VGA_H
|
#define VGA_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define VGA_WIDTH 640
|
typedef struct {
|
||||||
#define VGA_HEIGHT 480
|
uint16_t width;
|
||||||
#define VGA_DEPTH 8
|
uint16_t height;
|
||||||
|
uint8_t depth;
|
||||||
void vga_init();
|
// Add other relevant settings like color palette, etc.
|
||||||
void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth);
|
} vga_display_settings_t;
|
||||||
void vga_draw_pixel(uint16_t x, uint16_t y, uint8_t color);
|
|
||||||
void vga_clear_screen(uint8_t color);
|
void vga_init();
|
||||||
|
void vga_set_resolution(uint16_t width, uint16_t height, uint8_t depth);
|
||||||
#endif
|
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 "keyboard.h"
|
||||||
#include "../io/io.h"
|
#include "../io/io.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Keyboard input buffer
|
// Keyboard input buffer
|
||||||
#define KEYBOARD_BUFFER_SIZE 32
|
#define KEYBOARD_BUFFER_SIZE 32
|
||||||
#define KEYBOARD_DATA_PORT 0x60
|
#define KEYBOARD_DATA_PORT 0x60
|
||||||
#define KEYBOARD_INTERRUPT_VECTOR 0x09
|
#define KEYBOARD_INTERRUPT_VECTOR 0x09
|
||||||
#define KEYBOARD_COMMAND_PORT 0x64
|
#define KEYBOARD_COMMAND_PORT 0x64
|
||||||
#define KEYBOARD_DATA_PORT 0x60
|
#define KEYBOARD_DATA_PORT 0x60
|
||||||
#define KEYBOARD_ENABLE_COMMAND 0xAE
|
#define KEYBOARD_ENABLE_COMMAND 0xAE
|
||||||
#define KEYBOARD_ENABLE_SCANCODE 0xF4
|
#define KEYBOARD_ENABLE_SCANCODE 0xF4
|
||||||
#define KEYBOARD_ACKNOWLEDGE_SCANCODE 0xFA
|
#define KEYBOARD_ACKNOWLEDGE_SCANCODE 0xFA
|
||||||
|
#define KEYCODE_UNKNOWN 0xFF
|
||||||
static uint8_t keyboard_buffer[KEYBOARD_BUFFER_SIZE];
|
#define KEYCODE_C 0x03
|
||||||
static size_t keyboard_buffer_head = 0;
|
|
||||||
static size_t keyboard_buffer_tail = 0;
|
static uint8_t keyboard_buffer[KEYBOARD_BUFFER_SIZE];
|
||||||
|
static size_t keyboard_buffer_head = 0;
|
||||||
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
static size_t keyboard_buffer_tail = 0;
|
||||||
void enable_interrupt(uint8_t vector);
|
|
||||||
|
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
||||||
void KeyboardInterruptHandler()
|
void enable_interrupt(uint8_t vector);
|
||||||
{
|
|
||||||
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
|
void KeyboardInterruptHandler()
|
||||||
|
{
|
||||||
// Add scancode to buffer
|
uint8_t scancode = inb(KEYBOARD_DATA_PORT);
|
||||||
keyboard_buffer[keyboard_buffer_head] = scancode;
|
uint8_t keycode = translate_scancode_to_keycode(scancode);
|
||||||
keyboard_buffer_head = (keyboard_buffer_head + 1) % KEYBOARD_BUFFER_SIZE;
|
|
||||||
}
|
// Add scancode to buffer
|
||||||
|
keyboard_buffer[keyboard_buffer_head] = scancode;
|
||||||
// Initialize keyboard
|
keyboard_buffer_head = (keyboard_buffer_head + 1) % KEYBOARD_BUFFER_SIZE;
|
||||||
void keyboard_init()
|
}
|
||||||
{
|
|
||||||
// Install keyboard interrupt handler
|
uint8_t translate_scancode_to_keycode(uint8_t scancode)
|
||||||
//set_interrupt_vector(KEYBOARD_INTERRUPT_VECTOR, KeyboardInterruptHandler);
|
{
|
||||||
//enable_interrupt(KEYBOARD_INTERRUPT_VECTOR);
|
static uint8_t keycode_map[128] = {
|
||||||
|
[0x01] = KEYCODE_ESC,
|
||||||
// Enable keyboard
|
[0x02] = KEYCODE_1,
|
||||||
outb(KEYBOARD_COMMAND_PORT, KEYBOARD_ENABLE_COMMAND);
|
[0x03] = KEYCODE_2,
|
||||||
while (inb(KEYBOARD_COMMAND_PORT) & 0x02)
|
[0x04] = KEYCODE_3,
|
||||||
;
|
[0x05] = KEYCODE_4,
|
||||||
outb(KEYBOARD_DATA_PORT, KEYBOARD_ENABLE_SCANCODE);
|
[0x06] = KEYCODE_5,
|
||||||
while (inb(KEYBOARD_DATA_PORT) != KEYBOARD_ACKNOWLEDGE_SCANCODE)
|
[0x07] = KEYCODE_6,
|
||||||
;
|
[0x08] = KEYCODE_7,
|
||||||
}
|
[0x09] = KEYCODE_8,
|
||||||
|
[0x0A] = KEYCODE_9,
|
||||||
// Check if keyboard buffer is empty
|
[0x0B] = KEYCODE_0,
|
||||||
bool keyboard_buffer_empty()
|
[0x0C] = KEYCODE_MINUS,
|
||||||
{
|
[0x0D] = KEYCODE_EQUALS,
|
||||||
return keyboard_buffer_head == keyboard_buffer_tail;
|
[0x0E] = KEYCODE_BACKSPACE,
|
||||||
}
|
// ... (complete the rest based on the scancode table)
|
||||||
|
[0xE0] = 0, // Handle extended scancodes (e.g., Print Screen) separately
|
||||||
// Read scancode from keyboard buffer
|
};
|
||||||
uint8_t keyboard_read_scancode()
|
|
||||||
{
|
if (scancode < sizeof(keycode_map))
|
||||||
if (keyboard_buffer_empty())
|
{
|
||||||
{
|
// Map scancode directly to keycode
|
||||||
return 0;
|
return keycode_map[scancode];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
uint8_t scancode = keyboard_buffer[keyboard_buffer_tail];
|
{
|
||||||
keyboard_buffer_tail = (keyboard_buffer_tail + 1) % KEYBOARD_BUFFER_SIZE;
|
// Handle unknown scancode
|
||||||
return 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
|
#ifndef KEYBOARD_H
|
||||||
#define KEYBOARD_H
|
#define KEYBOARD_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void KeyboardInterruptHandler();
|
void KeyboardInterruptHandler();
|
||||||
|
|
||||||
void keyboard_init();
|
void keyboard_init();
|
||||||
bool keyboard_buffer_empty();
|
bool keyboard_buffer_empty();
|
||||||
uint8_t keyboard_read_scancode();
|
uint8_t keyboard_read_scancode();
|
||||||
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
void set_interrupt_vector(uint8_t vector, void (*handler)());
|
||||||
void enable_interrupt(uint8_t vector);
|
void enable_interrupt(uint8_t vector);
|
||||||
|
uint8_t translate_scancode_to_keycode(uint8_t scancode);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,98 +1,98 @@
|
|||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "isr/isr.h"
|
#include "isr/isr.h"
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
#define BYTE_MASK 0xFF
|
#define BYTE_MASK 0xFF
|
||||||
#define PAGE_FAULT 14
|
#define PAGE_FAULT 14
|
||||||
#define DOUBLE_FAULT 8
|
#define DOUBLE_FAULT 8
|
||||||
#define SYSTEM_CALL 80
|
#define SYSTEM_CALL 80
|
||||||
#define TIMER 20
|
#define TIMER 20
|
||||||
|
|
||||||
#define ISR_TABLE_SIZE 256
|
#define ISR_TABLE_SIZE 256
|
||||||
|
|
||||||
// GDT table
|
// GDT table
|
||||||
struct gdt_entry *gdt;
|
struct gdt_entry gdt_entries[3] __attribute__((aligned(0x1000)));
|
||||||
|
|
||||||
// GDT constants
|
// GDT constants
|
||||||
enum GDT_ACCESS
|
enum GDT_ACCESS
|
||||||
{
|
{
|
||||||
GDT_ACCESS_PRESENT = 0x80
|
GDT_ACCESS_PRESENT = 0x80
|
||||||
};
|
};
|
||||||
|
|
||||||
// GDT base and limit constants
|
// GDT base and limit constants
|
||||||
enum GDT_BASE_LIMIT
|
enum GDT_BASE_LIMIT
|
||||||
{
|
{
|
||||||
GDT_BASE_MIDDLE_SHIFT = 16,
|
GDT_BASE_MIDDLE_SHIFT = 16,
|
||||||
GDT_BASE_HIGH_SHIFT = 24,
|
GDT_BASE_HIGH_SHIFT = 24,
|
||||||
GDT_GRANULARITY_SHIFT = 16,
|
GDT_GRANULARITY_SHIFT = 16,
|
||||||
GDT_GRANULARITY_MASK = 0x0F,
|
GDT_GRANULARITY_MASK = 0x0F,
|
||||||
GDT_ACCESS_MASK = 0xF0,
|
GDT_ACCESS_MASK = 0xF0,
|
||||||
GDT_LIMIT_MASK = 0xFFFF
|
GDT_LIMIT_MASK = 0xFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void LoadGDT(struct gdt_ptr* gdt);
|
extern void LoadGDT(struct gdt_ptr* gdt);
|
||||||
|
|
||||||
// Initialize a GDT entry
|
// Initialize a GDT entry
|
||||||
void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access,
|
void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access,
|
||||||
uint8_t gran, struct gdt_entry *const gdt)
|
uint8_t gran, struct gdt_entry *const gdt)
|
||||||
{
|
{
|
||||||
gdt[num].base_low = (base & GDT_LIMIT_MASK);
|
gdt[num].base_low = (base & GDT_LIMIT_MASK);
|
||||||
gdt[num].base_middle = (base >> GDT_BASE_MIDDLE_SHIFT) & BYTE_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].base_high = (base >> GDT_BASE_HIGH_SHIFT) & BYTE_MASK;
|
||||||
gdt[num].limit_low = (limit & GDT_LIMIT_MASK);
|
gdt[num].limit_low = (limit & GDT_LIMIT_MASK);
|
||||||
gdt[num].granularity =
|
gdt[num].granularity =
|
||||||
(limit >> GDT_GRANULARITY_SHIFT) & GDT_GRANULARITY_MASK;
|
(limit >> GDT_GRANULARITY_SHIFT) & GDT_GRANULARITY_MASK;
|
||||||
gdt[num].granularity |= gran & GDT_ACCESS_MASK;
|
gdt[num].granularity |= gran & GDT_ACCESS_MASK;
|
||||||
gdt[num].access = access;
|
gdt[num].access = access;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdt_init()
|
void gdt_init()
|
||||||
{
|
{
|
||||||
// Set up GDT pointer
|
// Set up GDT pointer
|
||||||
struct gdt_ptr gp;
|
struct gdt_ptr gp;
|
||||||
gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
|
gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
|
||||||
//gdt = (struct gdt_entry *)malloc(sizeof(struct gdt_entry) * 3);
|
//gdt = (struct gdt_entry *)malloc(sizeof(struct gdt_entry) * 3);
|
||||||
//memset(gdt, 0, sizeof(struct gdt_entry) * 3);
|
//memset(gdt, 0, sizeof(struct gdt_entry) * 3);
|
||||||
|
|
||||||
// Initialize GDT entries
|
// Initialize GDT entries
|
||||||
gdt_set_gate(0, 0, 0, 0, 0, gdt); // Null segment
|
gdt_set_gate(0, 0, 0, 0, 0, &gdt_entries[0]); // Null segment
|
||||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF, gdt); // Code segment
|
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF, &gdt_entries[1]); // Code segment
|
||||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF, gdt); // Data segment
|
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF, &gdt_entries[2]); // Data segment
|
||||||
|
|
||||||
// Load GDT
|
// Load GDT
|
||||||
struct gdt_ptr gdtp;
|
struct gdt_ptr gdtp;
|
||||||
gdtp.limit = gp.limit;
|
gdtp.limit = gp.limit;
|
||||||
gdtp.base = (uintptr_t)gdt;
|
gdtp.base = (uintptr_t)gdt;
|
||||||
|
|
||||||
LoadGDT(&gdtp);
|
LoadGDT(&gdtp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
__asm__ volatile("mov $0x10, %ax\n\t"
|
__asm__ volatile("mov $0x10, %ax\n\t"
|
||||||
"mov %ax, %ds\n\t"
|
"mov %ax, %ds\n\t"
|
||||||
"mov %ax, %es\n\t"
|
"mov %ax, %es\n\t"
|
||||||
"mov %ax, %fs\n\t"
|
"mov %ax, %fs\n\t"
|
||||||
"mov %ax, %gs\n\t"
|
"mov %ax, %gs\n\t"
|
||||||
"ljmp $0x08, $next_label\n\t"
|
"ljmp $0x08, $next_label\n\t"
|
||||||
"next_label:");
|
"next_label:");
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exception handlers
|
// Exception handlers
|
||||||
extern void divide_error(struct idt_regs *regs);
|
extern void divide_error(struct idt_regs *regs);
|
||||||
extern void page_fault(struct idt_regs *regs);
|
extern void page_fault(struct idt_regs *regs);
|
||||||
extern void general_protection_fault();
|
extern void general_protection_fault();
|
||||||
extern void double_fault();
|
extern void double_fault();
|
||||||
|
|
||||||
// Interrupt handlers
|
// Interrupt handlers
|
||||||
extern void system_call();
|
extern void system_call();
|
||||||
extern void timer();
|
extern void timer();
|
||||||
extern void keyboard();
|
extern void keyboard();
|
||||||
extern void device();
|
extern void device();
|
||||||
|
@ -2,5 +2,6 @@ global LoadIDT
|
|||||||
|
|
||||||
section .text
|
section .text
|
||||||
LoadIDT:
|
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
|
RET
|
@ -1,19 +1,32 @@
|
|||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "isr/isr.h"
|
#include "../../../drivers/keyboard/keyboard.h"
|
||||||
#include "../../../drivers/keyboard/keyboard.h"
|
#include "isr/isr.h"
|
||||||
|
#include <stdint.h>
|
||||||
struct idt_entry idt[256];
|
|
||||||
|
struct idt_entry idt[256];
|
||||||
extern void LoadIDT(struct idt_entry* entry);
|
|
||||||
|
extern void LoadIDT(struct idt_entry *entry);
|
||||||
// Initialize the IDT
|
|
||||||
void InitializeIDT()
|
void TimerInterruptHandler()
|
||||||
{
|
{
|
||||||
idt[KEYBOARD_INTERRUPT].base_lo = ((uint16_t*)KeyboardInterruptHandler)[0];
|
static uint16_t timer_count = 0;
|
||||||
idt[KEYBOARD_INTERRUPT].sel = 0x08;
|
timer_count++;
|
||||||
idt[KEYBOARD_INTERRUPT].always0 = 0x00;
|
}
|
||||||
idt[KEYBOARD_INTERRUPT].flags = 0x8E;
|
|
||||||
idt[KEYBOARD_INTERRUPT].base_hi = ((uint16_t*)KeyboardInterruptHandler)[1];
|
// Initialize the IDT
|
||||||
|
void InitializeIDT()
|
||||||
LoadIDT(&idt[KEYBOARD_INTERRUPT]);
|
{
|
||||||
}
|
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