From ad70cfd8366d97c195f6aa38133e6eb65be13c4e Mon Sep 17 00:00:00 2001 From: Greg Bowne Date: Tue, 26 Mar 2024 00:59:15 -0700 Subject: [PATCH] did some more work on keyboard.c and bootloader and moved and other random stuff --- .vscode/browse.vc.db | Bin 33939456 -> 33939456 bytes .vscode/browse.vc.db-shm | Bin 32768 -> 32768 bytes src/boot/boot.asm | 35 ++++---- src/boot/boot.bin | Bin 0 -> 512 bytes src/boot/boot2.bin | Bin 0 -> 512 bytes src/drivers/io/io.asm | 2 +- src/drivers/io/io.c | 121 +++++++++++++-------------- src/drivers/io/io.h | 56 ++++++------- src/drivers/keyboard/keyboard.c | 116 +++++++++++++++++++++++-- src/drivers/keyboard/keyboard.h | 9 +- src/drivers/network/ne2000.c | 83 +++++++++--------- src/kernel/arch/x86/isr/exceptions.c | 27 ++++-- src/kernel/arch/x86/isr/isr.c | 20 +++++ 13 files changed, 303 insertions(+), 166 deletions(-) create mode 100644 src/boot/boot.bin create mode 100644 src/boot/boot2.bin diff --git a/.vscode/browse.vc.db b/.vscode/browse.vc.db index 0da4a0d04bee1133668435113af3e84f76119f17..6ddf39ba2102eb0f4f4bf300a2d02766b0fd0c81 100644 GIT binary patch delta 58141 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 delta 35578 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 diff --git a/.vscode/browse.vc.db-shm b/.vscode/browse.vc.db-shm index 795ab0e70a110a7b1ee150a6ed2f1cf0414f0801..c21ceaf119596ef09f236dfdaaa7cced72f21bdd 100644 GIT binary patch delta 205 zcmZo@U}|V!N|1P@%K!pTftZnjK>@_p7hquUJoajqzD~WM?+wBB_gY=tC0FXM#4R;5 zAXWXu1Oq*NpqcVO!*6o}%_hj+xKG4s;{z?`&3{}kuugn%jh&f+je(PaXX8alK6Vxc ab_Om6-i;Rc#&jbLZBr-n$ delta 210 zcmZo@U}|V!N|1P@%K!p$K+MR%pa5d)3otP3_|5rQFYBOyxXFpSmXaII4Cl92Zw-@O zPOAEe2?lz0Kr{J(hVuilI1oz#u{;oC7vH!~#EF@WfoJ1Ib>_`~TraRPvor8+y!e@q lnS+6E<3)L1W)=pnjTe72F|#soZ@f64kC~Z)bK}KIHUM#2F@yjB diff --git a/src/boot/boot.asm b/src/boot/boot.asm index 926dd31..9bb09e7 100644 --- a/src/boot/boot.asm +++ b/src/boot/boot.asm @@ -26,7 +26,7 @@ jmp start ; Data ; ;;;;;;;; ; fdd geometry & options -fddsamt db 8 ; how many sectors to load +fddsamt db 1 ; how many sectors to load fddretr db 5 ; max retries for fdd operations fddcretr db 0 ; current retries left @@ -76,52 +76,51 @@ start: hddload: mov si, diskhdd ; print disk type call printstr - - jmp halt ; not implemented! + jmp load_onto_reset fddload: mov si, diskfdd ; print disk type call printstr -fddload_onto_reset: +load_onto_reset: mov ah, [fddretr] ; load max retries in memory mov [fddcretr], ah -fddload_reset: +load_reset: mov si, fdderes ; load error message pointer dec byte [fddcretr] ; decrement the retries counter - jz fddload_err ; if it is 0, we stop trying + jz load_err ; if it is 0, we stop trying mov ah, 0x00 ; otherwise, reset function (int 0x13) int 0x13 - jc fddload_reset ; if jc (error), we try again + jc load_reset ; if jc (error), we try again -fddload_onto_load: +load_onto_load: mov ah, [fddretr] ; reset retries counter mov [fddcretr], ah - mov ax, 0x1000 ; need to stay within real mode limits + mov ax, 0x8000 ; need to stay within real mode limits mov es, ax -fddload_load: ; loads 512*fddsamt bytes from sector 2 on. +load_load: ; loads 512*fddsamt bytes from sector 2 on. mov si, fddeload dec byte [fddcretr] - jz fddload_err + jz load_err mov dh, 0 ; head 0 mov ch, 0 ; cyl/track 0 mov cl, 2 ; start sector - mov bx, 0 ; memory location + mov bx, 0x8000 ; memory location mov al, [fddsamt] ; how many sectors to read mov ah, 0x02 ; read function (int 0x13) int 0x13 - jc fddload_load ; if jc (error), we try again + jc load_load ; if jc (error), we try again cmp al, [fddsamt] ; also if al is not 1, we have a problem - jnz fddload_load + jnz load_load -fddload_done: +load_done: mov si, loaded ; we have successfully loaded the data call printstr - jmp halt ; this will be jmp 0x1000:0x0000 + jmp 0x8000:0x0000 ; this will be jmp 0x1000:0x0000 -fddload_err: +load_err: call printstr ; print jmp halt ; and die @@ -163,4 +162,4 @@ times 510 - ($ - $$) db 0x00 ;;;;;;;;;;;;;;;;;; ; BIOS signature ; ;;;;;;;;;;;;;;;;;; -dw 0xAA55 +dw 0xAA55 \ No newline at end of file diff --git a/src/boot/boot.bin b/src/boot/boot.bin new file mode 100644 index 0000000000000000000000000000000000000000..f866128d729fa1375f8e4ae4d04baca976bd7dd3 GIT binary patch literal 512 zcmaFa#K6eP5T2TooS&PjP?E1ul98(5oRe5woSEz&tPot1n4YR&sF0MOUy_rbn37tg z$IHdwQj}Q+R9sn*YNf#7=Hdbr@&J=Ai6w~&V09^qKtZ6CLQ!gQYKcNxVrEWi3P>+R zEHMR1h{5nc-;KTl9bzptTNrmTFrF3I!f{q$A6w0fB8GjYH7{})x`0v*j~Yri_IcF2 zh-G-qw$G{NMJPj;8cR)w8f(qI*qVQQtTiR}TNus?7kz{Y?_g-?JFu@1BB#8KVJpK% zrrit;3z%!RFagy)wPItgDZRhXujU08!z%^`hK3hR46k|rtl>CN!nTF)tibE9hkw2P L3zQhPAaoS~b7E_! literal 0 HcmV?d00001 diff --git a/src/boot/boot2.bin b/src/boot/boot2.bin new file mode 100644 index 0000000000000000000000000000000000000000..4b83fe4f97fad9a1848a6d653cf2b9f360ca3f33 GIT binary patch literal 512 zcmaFO?d=-m=jx;9v~5hF=JT Gt^xpV7!;WR literal 0 HcmV?d00001 diff --git a/src/drivers/io/io.asm b/src/drivers/io/io.asm index 3716ae1..d7a332c 100644 --- a/src/drivers/io/io.asm +++ b/src/drivers/io/io.asm @@ -16,7 +16,7 @@ inb: outb: PUSH DX ; Preserve DX PUSH AX ; Preserve AX - MOV DX, [ESP + 4] ; Get port number from stack + MOV DX, [ESP + 6] ; Get port number from stack MOV AL, [ESP + 6] ; Get data from stack OUT DX, AL ; Write to port POP AX ; Restore AX diff --git a/src/drivers/io/io.c b/src/drivers/io/io.c index 28a0753..fc278da 100644 --- a/src/drivers/io/io.c +++ b/src/drivers/io/io.c @@ -1,63 +1,58 @@ -#include "io.h" - -/* - Common Ports - COM1: 0x3F8 - COM2: 0x2F8 - COM3: 0x3E8 - COM4: 0x2E8 - LPT1: 0x378 - LPT2: 0x278 - LPT3: 0x3BC -*/ - -// Function to initialize the COM and LPT ports -void io_init() -{ - // TODO: Initialize the COM and LPT ports - // Set up any necessary configuration or control operations -} - -// Function to read from the COM port -char io_read_com() -{ - // TODO: Read from the COM port - // Use the appropriate memory or I/O address to read from the port - // Return the read data - - char data = 0; // Initialize the variable to store the read data - - // Read from the COM port and assign the read value to the 'data' variable - - return data; // Return the read data -} - -// Function to write to the COM port -void io_write_com(char data) -{ - // TODO: Write to the COM port - // Use the appropriate memory or I/O address to write to the port - // Write the provided data to the port -} - -// Function to read from the LPT port -char io_read_lpt() -{ - // TODO: Read from the LPT port - // Use the appropriate memory or I/O address to read from the port - // Return the read data - - char data = 0; // Initialize the variable to store the read data - - // Read from the LPT port and assign the read value to the 'data' variable - - return data; // Return the read data -} - -// Function to write to the LPT port -void io_write_lpt(char data) -{ - // TODO: Write to the LPT port - // Use the appropriate memory or I/O address to write to the port - // Write the provided data to the port -} \ No newline at end of file +#include "io.h" + +/* + Common Ports + COM1: 0x3F8 + COM2: 0x2F8 + COM3: 0x3E8 + COM4: 0x2E8 + COM5: 0x5F8 + COM6: 0x4F8 + COM7: 0x5E8 + COM8: 0x4E8 + LPT1: 0x378 + LPT2: 0x278 + LPT3: 0x3BC +*/ + +// Function to initialize the ports before reading or writing +void io_init() +{ + // Initialize COM1 port (0x3F8) - You can add more port initializations here if needed + + // Example initialization for COM1 port (9600 baud, 8N1) + outb(0x3F8 + 1, 0x00); // Disable all interrupts + outb(0x3F8 + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(0x3F8 + 0, 0x03); // Set divisor to 3 (lo byte) for 9600 baud rate + outb(0x3F8 + 1, 0x00); // Set divisor to hi byte for 9600 baud rate (default) + outb(0x3F8 + 3, 0x03); // Set data format to 8N1 (8 data bits, no parity, one stop bit) + +} + +// Function to read from the COM port +char io_read_com() +{ + // Read from COM1 port 0x3F8 + return inb(0x3F8); // Read data from COM1 port +} + +// Function to write to the COM port +void io_write_com(char data) +{ + // Write to COM1 port 0x3F8 + outb(0x3F8, data); // Write data to COM1 port +} + +// Function to read from the LPT port +char io_read_lpt() +{ + // Read from LPT1 port 0x378 + return inb(0x378); // Read data from LPT1 port +} + +// Function to write to the LPT port +void io_write_lpt(char data) +{ + // Write to LPT1 port 0x378 + outb(0x378, data); // Write data to LPT1 port +} diff --git a/src/drivers/io/io.h b/src/drivers/io/io.h index 09bd4bc..3f72309 100644 --- a/src/drivers/io/io.h +++ b/src/drivers/io/io.h @@ -1,28 +1,28 @@ -#ifndef IO_H -#define IO_H - -#include - -// Function to initialize the COM and LPT ports -void io_init(); - -// Function to read from the COM port -char io_read_com(); - -// Function to write to the COM port -void io_write_com(char data); - -// Function to read from the LPT port -char io_read_lpt(); - -// Function to write to the LPT port -void io_write_lpt(char data); - -// Function declarations for keyboard.c -extern uint8_t inb(uint16_t port); - -extern void outb(uint16_t port, uint8_t data); - -void install_interrupt_handler(uint8_t interrupt, void (*handler)(void)); - -#endif /* IO_H */ \ No newline at end of file +#ifndef IO_H +#define IO_H + +#include + +// Function to initialize the COM and LPT ports +void io_init(); + +// Function to read from the COM port +char io_read_com(); + +// Function to write to the COM port +void io_write_com(char data); + +// Function to read from the LPT port +char io_read_lpt(); + +// Function to write to the LPT port +void io_write_lpt(char data); + +// Function declarations for keyboard.c +extern uint8_t inb(uint16_t port); + +extern void outb(uint16_t port, uint8_t data); + +void install_interrupt_handler(uint8_t interrupt, void (*handler)(void)); + +#endif /* IO_H */ diff --git a/src/drivers/keyboard/keyboard.c b/src/drivers/keyboard/keyboard.c index e5771ea..87e0b98 100644 --- a/src/drivers/keyboard/keyboard.c +++ b/src/drivers/keyboard/keyboard.c @@ -9,7 +9,6 @@ #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 @@ -33,6 +32,21 @@ void KeyboardInterruptHandler() keyboard_buffer_head = (keyboard_buffer_head + 1) % KEYBOARD_BUFFER_SIZE; } +// Function to translate the combined extended scancode (first byte + second byte) +uint8_t translate_extended_scancode(uint8_t second_scancode) +{ + uint16_t combined_scancode = (0xE0 << 8) | second_scancode; + + switch(combined_scancode) + { + case 0xE04D: + return KEYCODE_PRINT_SCREEN; + // Add more cases for other extended scancodes here + default: + return KEYCODE_UNKNOWN; + } +} + uint8_t translate_scancode_to_keycode(uint8_t scancode) { static uint8_t keycode_map[128] = { @@ -50,19 +64,109 @@ uint8_t translate_scancode_to_keycode(uint8_t scancode) [0x0C] = KEYCODE_MINUS, [0x0D] = KEYCODE_EQUALS, [0x0E] = KEYCODE_BACKSPACE, + [0x0F] = KEYCODE_TAB, + [0x10] = KEYCODE_Q, + [0x11] = KEYCODE_W, + [0x12] = KEYCODE_E, + [0x13] = KEYCODE_R, + [0x14] = KEYCODE_T, + [0x15] = KEYCODE_Y, + [0x16] = KEYCODE_U, + [0x17] = KEYCODE_I, + [0x18] = KEYCODE_O, + [0x19] = KEYCODE_P, + [0x1A] = KEYCODE_LEFT_BRACKET, + [0x1B] = KEYCODE_RIGHT_BRACKET, + [0x1C] = KEYCODE_ENTER, + [0x1D] = KEYCODE_LEFT_CTRL, + [0x1E] = KEYCODE_A, + [0x1F] = KEYCODE_S, + [0x20] = KEYCODE_D, + [0x21] = KEYCODE_F, + [0x22] = KEYCODE_G, + [0x23] = KEYCODE_H, + [0x24] = KEYCODE_J, + [0x25] = KEYCODE_K, + [0x26] = KEYCODE_L, + [0x27] = KEYCODE_SEMICOLON, + [0x28] = KEYCODE_APOSTROPHE, + [0x29] = KEYCODE_GRAVE_ACCENT, + [0x2A] = KEYCODE_LEFT_SHIFT, + [0x2B] = KEYCODE_BACKSLASH, + [0x2C] = KEYCODE_Z, + [0x2D] = KEYCODE_X, + [0x2E] = KEYCODE_C, + [0x2F] = KEYCODE_V, + [0x30] = KEYCODE_B, + [0x31] = KEYCODE_N, + [0x32] = KEYCODE_M, + [0x33] = KEYCODE_COMMA, + [0x34] = KEYCODE_DOT, + [0x35] = KEYCODE_FORWARD_SLASH, + [0x36] = KEYCODE_RIGHT_SHIFT, + [0x37] = KEYCODE_PRINT_SCREEN, // Example extended scancode (replace with more) + [0x38] = KEYCODE_LEFT_ALT, + [0x39] = KEYCODE_SPACE, + [0x3A] = KEYCODE_CAPS_LOCK, + [0x3B] = KEYCODE_F1, + [0x3C] = KEYCODE_F2, + [0x3D] = KEYCODE_F3, + [0x3E] = KEYCODE_F4, + [0x3F] = KEYCODE_F5, + [0x40] = KEYCODE_F6, + [0x41] = KEYCODE_F7, + [0x41] = KEYCODE_F7, + [0x42] = KEYCODE_F8, + [0x43] = KEYCODE_F9, + [0x44] = KEYCODE_F10, + [0x45] = KEYCODE_NUM_LOCK, // Extended scancode + [0x46] = KEYCODE_SCROLL_LOCK, // Extended scancode + [0x47] = KEYCODE_HOME, + [0x48] = KEYCODE_UP, + [0x49] = KEYCODE_PAGE_UP, + [0x4A] = KEYCODE_MINUS_PAD, + [0x4B] = KEYCODE_LEFT_ARROW, + [0x4C] = KEYCODE_5_PAD, + [0x4D] = KEYCODE_RIGHT_ARROW, + [0x4E] = KEYCODE_PLUS_PAD, + [0x4F] = KEYCODE_END, + [0x50] = KEYCODE_DOWN_ARROW, + [0x51] = KEYCODE_PAGE_DOWN, + [0x52] = KEYCODE_INSERT, + [0x53] = KEYCODE_DELETE, + // ... (complete the rest based on the scancode table) [0xE0] = 0, // Handle extended scancodes (e.g., Print Screen) separately }; - if (scancode < sizeof(keycode_map)) + static bool extended_scancode = false; + static uint8_t second_scancode; + + if (extended_scancode) { - // Map scancode directly to keycode - return keycode_map[scancode]; + // Handle second byte of extended scancode + extended_scancode = false; + return translate_extended_scancode(scancode); // Implement separate function for extended keycode translation + } + else if (scancode == 0xE0) + { + // First byte of extended scancode sequence + extended_scancode = true; + return 0; // Indicate incomplete scancode (waiting for second byte) } else { - // Handle unknown scancode - return KEYCODE_UNKNOWN; // Or return a special keycode indicating error + // Regular scancode + if (scancode < sizeof(keycode_map)) + { + // Map scancode directly to keycode + return keycode_map[scancode]; + } + else + { + // Handle unknown scancode + return KEYCODE_UNKNOWN; + } } } diff --git a/src/drivers/keyboard/keyboard.h b/src/drivers/keyboard/keyboard.h index 97960e1..7579c08 100644 --- a/src/drivers/keyboard/keyboard.h +++ b/src/drivers/keyboard/keyboard.h @@ -6,10 +6,11 @@ void KeyboardInterruptHandler(); -void keyboard_init(); -bool keyboard_buffer_empty(); +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); +void set_interrupt_vector(uint8_t vector, void (*handler)()); +void enable_interrupt(uint8_t vector); uint8_t translate_scancode_to_keycode(uint8_t scancode); +uint8_t translate_extended_scancode(uint8_t second_scancode); #endif diff --git a/src/drivers/network/ne2000.c b/src/drivers/network/ne2000.c index 048ac62..30877ad 100644 --- a/src/drivers/network/ne2000.c +++ b/src/drivers/network/ne2000.c @@ -1,41 +1,42 @@ -#include - -// NE2000 registers -#define NE2000_COMMAND 0x00 -#define NE2000_PSTART 0x01 -#define NE2000_PSTOP 0x02 -// ... more registers ... - -// NE2000 commands -#define NE2000_CMD_START 0x02 -#define NE2000_CMD_STOP 0x01 -// ... more commands ... - -// Write a value to a NE2000 register -void ne2000_write_reg(uint16_t base_addr, uint8_t reg, uint8_t value) { - // Write to the register - // This will depend on your specific hardware interface -} - -// Read a value from a NE2000 register -uint8_t ne2000_read_reg(uint16_t base_addr, uint8_t reg) { - // Read from the register - // This will depend on your specific hardware interface -} - -// Initialize the NE2000 card -void ne2000_init(uint16_t base_addr) { - // Stop the NE2000 card - ne2000_write_reg(base_addr, NE2000_COMMAND, NE2000_CMD_STOP); - - // Set up the packet buffer - ne2000_write_reg(base_addr, NE2000_PSTART, 0x40); - ne2000_write_reg(base_addr, NE2000_PSTOP, 0x80); - - // ... more initialization ... - - // Start the NE2000 card - ne2000_write_reg(base_addr, NE2000_COMMAND, NE2000_CMD_START); -} - -// ... more driver functions .. \ No newline at end of file +#include + +// NE2000 registers +#define NE2000_COMMAND 0x00 +#define NE2000_PSTART 0x01 +#define NE2000_PSTOP 0x02 +// ... more registers ... + +// NE2000 commands +#define NE2000_CMD_START 0x02 +#define NE2000_CMD_STOP 0x01 +// ... more commands ... + +// Write a value to a NE2000 register +void ne2000_write_reg(uint16_t base_addr, uint8_t reg, uint8_t value) { + volatile uint8_t *ne2000_reg = (volatile uint8_t *)(base_addr + reg); + *ne2000_reg = value; +} + +// Read a value from a NE2000 register +uint8_t ne2000_read_reg(uint16_t base_addr, uint8_t reg) { + volatile uint8_t *ne2000_reg = (volatile uint8_t *)(base_addr + reg); + return *ne2000_reg; +} + +// Initialize the NE2000 card +void ne2000_init(uint16_t base_addr) +{ + // Stop the NE2000 card + ne2000_write_reg(base_addr, NE2000_COMMAND, NE2000_CMD_STOP); + + // Set up the packet buffer + ne2000_write_reg(base_addr, NE2000_PSTART, 0x40); + ne2000_write_reg(base_addr, NE2000_PSTOP, 0x80); + + // ... more initialization ... + + // Start the NE2000 card + ne2000_write_reg(base_addr, NE2000_COMMAND, NE2000_CMD_START); +} + +// ... more driver functions .. diff --git a/src/kernel/arch/x86/isr/exceptions.c b/src/kernel/arch/x86/isr/exceptions.c index 0b35e7b..f0a197a 100644 --- a/src/kernel/arch/x86/isr/exceptions.c +++ b/src/kernel/arch/x86/isr/exceptions.c @@ -1,23 +1,40 @@ #include "exceptions.h" +#include +#include #include +#include void DivideByZero() { - //printf("Divide By Zero Exception"); + // Add logic to handle Divide By Zero Exception + printf("Divide By Zero Exception\n"); + + // Additional Exception Handling Logic: + // Example: Perform specific actions for Divide By Zero scenario + // - Log the exception to a file + FILE *logFile = fopen("error.log", "a"); + if (logFile != NULL) { + fprintf(logFile, "Divide By Zero Exception occurred\n"); + fclose(logFile); + } + + // - Gracefully terminate the kernel + printf("Exiting kernel due to Divide By Zero Exception\n"); + exit(EXIT_FAILURE); } void DoubleFault() { - //printf("Double Fault Exception"); + // printf("Double Fault Exception"); } void PageFault() { - //printf("Page Fault Exception"); + // printf("Page Fault Exception"); } void GeneralProtectionFault() { - //printf("General Protection Fault Exception"); -} \ No newline at end of file + // printf("General Protection Fault Exception"); +} diff --git a/src/kernel/arch/x86/isr/isr.c b/src/kernel/arch/x86/isr/isr.c index ecb5624..5f8d426 100644 --- a/src/kernel/arch/x86/isr/isr.c +++ b/src/kernel/arch/x86/isr/isr.c @@ -1 +1,21 @@ #include "isr.h" + +void isr_handler(struct isr_regs regs) { + switch(regs.int_no) { + case DIVIDE_BY_ZERO_INTERRUPT: + // Handle Divide By Zero Interrupt + break; + case DOUBLE_FAULT_INTERRUPT: + // Handle Double Fault Interrupt + break; + case PAGE_FAULT_INTERRUPT: + // Handle Page Fault Interrupt + break; + case GENERAL_PROTECTION_FAULT_INTERRUPT: + // Handle General Protection Fault Interrupt + break; + default: + // Handle other interrupts or implement error handling + break; + } +}