Trying FASM instead of TCC hybrid proved to be a good choise. Binary is layed out flat and sections are not rearranged so no need to worry about Multiboot structures moving around.
Also managed to get paging (first 4M is identity mapped, but hey it's a start).
This commit is contained in:
commit
cbaa9e00f9
17 changed files with 460 additions and 715 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
|||
*.elf
|
||||
*.o
|
||||
*.img
|
||||
*.bin
|
||||
mnt/
|
||||
build/
|
||||
|
|
16
Makefile
16
Makefile
|
@ -1,17 +1,15 @@
|
|||
all: build/kernel-i386.elf
|
||||
clean:
|
||||
-@rm build/*.o build/*.elf 2> /dev/null || true
|
||||
-@rm *.bin 2> /dev/null || true
|
||||
|
||||
build/start32.o: build/ src/start32.asm
|
||||
nasm -felf32 src/start32.asm -o build/start32.o
|
||||
build/kernel-i386.elf: build/start32.o
|
||||
tcc -m32 -nostdlib -Wl,-Ttext,0x100000 -o build/kernel-i386.elf src/*.c build/start32.o
|
||||
image: build/kernel-i386.elf mount
|
||||
cp build/kernel-i386.elf mnt/
|
||||
start32.bin: src/*
|
||||
fasm src/start32.asm start32.bin
|
||||
image: start32.bin mount
|
||||
cp start32.bin mnt/koalemos/
|
||||
sync
|
||||
|
||||
qemu-multiboot: build/kernel-i386.elf
|
||||
qemu-system-i386 -kernel build/kernel-i386.elf -serial stdio
|
||||
qemu-multiboot: start32.bin
|
||||
qemu-system-i386 -kernel start32.bin -serial stdio
|
||||
qemu-image: image
|
||||
qemu-system-i386 koalemos.img -serial stdio
|
||||
|
||||
|
|
|
@ -3,7 +3,4 @@ Multiboot compatible stupid useless OS-like project.
|
|||
## Compatibility
|
||||
32bit x86 legacy BIOS system
|
||||
## Building
|
||||
NASM and TinyCCompiler are used.
|
||||
TCC might need manual compilation for 32bit crosscompilation
|
||||
on 64bit systems.
|
||||
Just download the source and `make cross` or something.
|
||||
FASM is used as the assembler.
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#include "framebuffer.h"
|
||||
|
||||
static unsigned long fb_address;
|
||||
static unsigned long fb_pitch;
|
||||
static unsigned short fb_width, fb_height;
|
||||
static unsigned char fb_bpp, fb_bytespp;
|
||||
static unsigned char fb_rpos, fb_bpos, fb_gpos;
|
||||
|
||||
void initfb(unsigned long addr, unsigned short w, unsigned short h, unsigned char bpp, unsigned long pitch, unsigned char rpos, unsigned char gpos, unsigned char bpos) {
|
||||
fb_address = addr;
|
||||
fb_pitch = pitch;
|
||||
fb_width = w;
|
||||
fb_height = h;
|
||||
fb_bpp = bpp;
|
||||
fb_bytespp = bpp/8;
|
||||
fb_rpos = rpos;
|
||||
fb_gpos = gpos;
|
||||
fb_bpos = bpos;
|
||||
}
|
||||
|
||||
void putpixel(unsigned short x, unsigned short y, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
|
||||
if (x>fb_width || y> fb_height) return;
|
||||
*((unsigned long *)(fb_address + y*fb_pitch + x*fb_bytespp)) = r<<fb_rpos | g<<fb_gpos | b<<fb_bpos;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef _FRAMEBUFFER_H
|
||||
#define _FRAMEBUFFER_H 1
|
||||
|
||||
void initfb(unsigned long addr, unsigned short w, unsigned short h, unsigned char bpp, unsigned long pitch, unsigned char rpos, unsigned char gpos, unsigned char bpos);
|
||||
void putpixel(unsigned short x, unsigned short y, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
|
||||
#endif
|
98
src/itoa.asm
Normal file
98
src/itoa.asm
Normal file
|
@ -0,0 +1,98 @@
|
|||
;; Modified from: https://gist.github.com/SplittyDev/8e728627012e57ac0deac196660014fb
|
||||
|
||||
;
|
||||
; Routine to convert a 32-bit integer to a string.
|
||||
; Registers are preserved.
|
||||
;
|
||||
; EAX: Source integer
|
||||
; EBX: Target address
|
||||
; ECX: Base
|
||||
;
|
||||
; Internal register layout:
|
||||
; start:
|
||||
; EAX: Source integer
|
||||
; ECX: Target address
|
||||
; EDX: Base
|
||||
; checknegative:
|
||||
; EAX: Source integer
|
||||
; EBX: Target address (original)
|
||||
; ECX: Target address (active)
|
||||
; divrem:
|
||||
; EAX: Source integer
|
||||
; ECX: Target address (active)
|
||||
; EDX: Base / Result
|
||||
; reverse:
|
||||
; EBX: Target address (original)
|
||||
; ECX: Target address (active)
|
||||
; EDX: Target address (temporary)
|
||||
;
|
||||
__uitoa:
|
||||
.start:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
push edx
|
||||
|
||||
mov eax, [ebp+8]
|
||||
mov ecx, [ebp+12]
|
||||
mov ebx, [ebp+16]
|
||||
|
||||
mov edx, ecx
|
||||
mov ecx, ebx
|
||||
;.checknegative:
|
||||
; test eax, eax
|
||||
; jns .divrem
|
||||
; mov byte [ecx], 0x2D
|
||||
; inc ecx
|
||||
; mov ebx, ecx
|
||||
; neg eax
|
||||
.divrem:
|
||||
push edx
|
||||
push ecx
|
||||
mov ecx, edx
|
||||
xor edx, edx
|
||||
div ecx
|
||||
mov byte dl, [__itoacvt + edx]
|
||||
pop ecx
|
||||
mov byte [ecx], dl
|
||||
pop edx
|
||||
inc ecx
|
||||
cmp eax, 0x00
|
||||
jne .divrem
|
||||
mov byte [ecx], 0x00
|
||||
dec ecx
|
||||
.reverse:
|
||||
cmp ebx, ecx
|
||||
jge .end
|
||||
mov byte dl, [ebx]
|
||||
mov byte al, [ecx]
|
||||
mov byte [ebx], al
|
||||
mov byte [ecx], dl
|
||||
inc ebx
|
||||
dec ecx
|
||||
jmp .reverse
|
||||
.end:
|
||||
pop edx
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
;
|
||||
; Conversion table for __itoa.
|
||||
; Works for bases [2 ... 36].
|
||||
;
|
||||
__itoacvt:
|
||||
db '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
|
||||
;
|
||||
; Buffer to store the result of __itoa in.
|
||||
;
|
||||
align 64
|
||||
__itoabuf32:
|
||||
rb 36
|
83
src/kernel.c
83
src/kernel.c
|
@ -1,83 +0,0 @@
|
|||
#include "multiboot.h"
|
||||
#include "framebuffer.h"
|
||||
#include "serial.h"
|
||||
#include "xtoa.h"
|
||||
|
||||
static inline void outb(unsigned short port, unsigned char val) {
|
||||
asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
|
||||
}
|
||||
static inline unsigned char inb(unsigned short port) {
|
||||
unsigned char ret;
|
||||
asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kmain (unsigned int mbootmagick, multiboot_info_t* mbootinfo) {
|
||||
|
||||
// Cursor disabling
|
||||
outb(0x3D4, 0x0A);
|
||||
outb(0x3D5, 0x20);
|
||||
|
||||
int serial_initialized = serial_init();
|
||||
serial_write_string("\n=== KoalemOS ===\n");
|
||||
|
||||
// Check multiboot header
|
||||
if (mbootmagick != MULTIBOOT_BOOTLOADER_MAGIC) {
|
||||
return;
|
||||
}
|
||||
|
||||
serial_write_string("\nMultiboot flags: ");
|
||||
serial_write_string(itoa(mbootinfo->flags, 2));
|
||||
|
||||
// Check videomode
|
||||
if (mbootinfo->flags & MULTIBOOT_INFO_VBE_INFO) {
|
||||
serial_write_string("\nVBE Mode: 0x");
|
||||
serial_write_string(itoa(mbootinfo->vbe_mode, 16));
|
||||
}
|
||||
|
||||
if (!(mbootinfo->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO)) {
|
||||
serial_write_string("\nVideo info not available");
|
||||
return;
|
||||
}
|
||||
|
||||
serial_write_string("\nFramebuffer: ");
|
||||
serial_write_string("\n Address: 0x");
|
||||
serial_write_string(ultoa(mbootinfo->framebuffer_addr, 16));
|
||||
|
||||
serial_write_string("\n Dimensions: ");
|
||||
serial_write_string(itoa(mbootinfo->framebuffer_width, 10));
|
||||
serial_write_string("X");
|
||||
serial_write_string(itoa(mbootinfo->framebuffer_height, 10));
|
||||
serial_write_string("x");
|
||||
serial_write_string(itoa(mbootinfo->framebuffer_bpp, 10));
|
||||
serial_write_string("\n Pitch: ");
|
||||
serial_write_string(itoa(mbootinfo->framebuffer_pitch, 10));
|
||||
serial_write_string("\n RPos:");
|
||||
serial_write_string(itoa(mbootinfo->framebuffer_red_field_position, 10));
|
||||
serial_write_string("\n GPos:");
|
||||
serial_write_string(itoa(mbootinfo->framebuffer_green_field_position, 10));
|
||||
serial_write_string("\n BPos:");
|
||||
serial_write_string(itoa(mbootinfo->framebuffer_blue_field_position, 10));
|
||||
|
||||
serial_write_string("\nMemory: ");
|
||||
serial_write_string("\n lower: ");
|
||||
serial_write_string(uitoa(mbootinfo->mem_lower, 10));
|
||||
serial_write_string(" k");
|
||||
serial_write_string("\n upper: ");
|
||||
serial_write_string(uitoa(mbootinfo->mem_upper/1024, 10));
|
||||
serial_write_string(" M");
|
||||
|
||||
initfb(mbootinfo->framebuffer_addr, mbootinfo->framebuffer_width, mbootinfo->framebuffer_height, mbootinfo->framebuffer_bpp, mbootinfo->framebuffer_pitch, mbootinfo->framebuffer_red_field_position, mbootinfo->framebuffer_green_field_position, mbootinfo->framebuffer_blue_field_position);
|
||||
int x, y, i;
|
||||
unsigned char c = 0;
|
||||
for(;;) {
|
||||
for(y=0; y < mbootinfo->framebuffer_height; y++) {
|
||||
for(x=0; x < mbootinfo->framebuffer_width; x++) {
|
||||
putpixel(x, y, c, c, c, 0xff);
|
||||
}
|
||||
}
|
||||
c+=4;
|
||||
}
|
||||
|
||||
serial_write_string("\nExecution finished, halting...");
|
||||
}
|
118
src/mbootinfo.asm
Normal file
118
src/mbootinfo.asm
Normal file
|
@ -0,0 +1,118 @@
|
|||
mbootgetinfo:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
cld
|
||||
|
||||
mov eax, [ebp+8]
|
||||
cmp eax, 0x2badb002
|
||||
jne mbootnomagic
|
||||
|
||||
mov ebx, [ebp+12]
|
||||
mov eax, [ebx]
|
||||
mov [mbootinfo.flags], eax
|
||||
|
||||
;; Get memoryinformation
|
||||
test eax, 1b
|
||||
jz mbootnomeminfo
|
||||
mov eax, [ebx+4]
|
||||
mov [mbootinfo.mem_lower], eax
|
||||
mov eax, [ebx+8]
|
||||
mov [mbootinfo.mem_upper], eax
|
||||
|
||||
;; Get videoinformation
|
||||
test [mbootinfo.flags], (1 shl 02)
|
||||
jz mbootnovideoinfo
|
||||
|
||||
mov esi, ebx
|
||||
add esi, 88
|
||||
mov eax, [esi]
|
||||
mov [mbootinfo.fb_addr], eax
|
||||
add esi, 8
|
||||
|
||||
mov eax, [esi]
|
||||
mov [mbootinfo.fb_pitch], eax
|
||||
add esi, 4
|
||||
|
||||
mov eax, [esi]
|
||||
mov [mbootinfo.fb_width], eax
|
||||
add esi, 4
|
||||
|
||||
mov eax, [esi]
|
||||
mov [mbootinfo.fb_height], eax
|
||||
add esi, 4
|
||||
|
||||
mov al, [esi]
|
||||
cmp al, 32
|
||||
je .bppokay
|
||||
cmp al, 24
|
||||
je .bppokay
|
||||
jmp mbootunsupportedfbbpp
|
||||
.bppokay:
|
||||
mov [mbootinfo.fb_bpp], al
|
||||
inc esi
|
||||
|
||||
mov al, [esi]
|
||||
cmp al, 1
|
||||
jne mbootunsupportedfbtype
|
||||
mov [mbootinfo.fb_type], al
|
||||
inc esi
|
||||
|
||||
;; r/g/b positions and masks
|
||||
mov ecx, 6
|
||||
mov edi, mbootinfo.fb_rpos
|
||||
rep movsb
|
||||
|
||||
.done:
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
mbootnomagic:
|
||||
push .msg
|
||||
call serialwrite
|
||||
jmp hang
|
||||
.msg db "No multiboot magic!", 10, 0
|
||||
mbootnomeminfo:
|
||||
push .msg
|
||||
call serialwrite
|
||||
jmp hang
|
||||
.msg db "No memoryinfo!", 10, 0
|
||||
mbootnovideoinfo:
|
||||
push .msg
|
||||
call serialwrite
|
||||
jmp hang
|
||||
.msg db "No videoryinfo!", 10, 0
|
||||
mbootunsupportedfbtype:
|
||||
push .msg
|
||||
call serialwrite
|
||||
jmp hang
|
||||
.msg db "Unsupported framebuffer type: only direct RGB is supported!", 10, 0
|
||||
mbootunsupportedfbbpp:
|
||||
push .msg
|
||||
call serialwrite
|
||||
jmp hang
|
||||
.msg db "Unsupported bitdepth: only 24 and 32 bpp supported!", 10, 0
|
||||
|
||||
|
||||
mbootinfo:
|
||||
.flags dd 0
|
||||
.mem_lower dd 0
|
||||
.mem_upper dd 0
|
||||
.fb_addr dd 0
|
||||
.fb_pitch dd 0
|
||||
.fb_width dd 0
|
||||
.fb_height dd 0
|
||||
.fb_bpp db 0
|
||||
.fb_type db 0
|
||||
.fb_rpos db 0
|
||||
.fb_rmasksize db 0
|
||||
.fb_gpos db 0
|
||||
.fb_gmasksize db 0
|
||||
.fb_bpos db 0
|
||||
.fb_bmasksize db 0
|
274
src/multiboot.h
274
src/multiboot.h
|
@ -1,274 +0,0 @@
|
|||
/* multiboot.h - Multiboot header file. */
|
||||
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
|
||||
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MULTIBOOT_HEADER
|
||||
#define MULTIBOOT_HEADER 1
|
||||
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
#define MULTIBOOT_SEARCH 8192
|
||||
#define MULTIBOOT_HEADER_ALIGN 4
|
||||
|
||||
/* The magic field should contain this. */
|
||||
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
||||
|
||||
/* This should be in %eax. */
|
||||
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
|
||||
|
||||
/* Alignment of multiboot modules. */
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
|
||||
/* Alignment of the multiboot info structure. */
|
||||
#define MULTIBOOT_INFO_ALIGN 0x00000004
|
||||
|
||||
/* Flags set in the ’flags’ member of the multiboot header. */
|
||||
|
||||
/* Align all boot modules on i386 page (4KB) boundaries. */
|
||||
#define MULTIBOOT_PAGE_ALIGN 0x00000001
|
||||
|
||||
/* Must pass memory information to OS. */
|
||||
#define MULTIBOOT_MEMORY_INFO 0x00000002
|
||||
|
||||
/* Must pass video information to OS. */
|
||||
#define MULTIBOOT_VIDEO_MODE 0x00000004
|
||||
|
||||
/* This flag indicates the use of the address fields in the header. */
|
||||
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
|
||||
|
||||
/* Flags to be set in the ’flags’ member of the multiboot info structure. */
|
||||
|
||||
/* is there basic lower/upper memory information? */
|
||||
#define MULTIBOOT_INFO_MEMORY 0x00000001
|
||||
/* is there a boot device set? */
|
||||
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
|
||||
/* is the command-line defined? */
|
||||
#define MULTIBOOT_INFO_CMDLINE 0x00000004
|
||||
/* are there modules to do something with? */
|
||||
#define MULTIBOOT_INFO_MODS 0x00000008
|
||||
|
||||
/* These next two are mutually exclusive */
|
||||
|
||||
/* is there a symbol table loaded? */
|
||||
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
|
||||
/* is there an ELF section header table? */
|
||||
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
|
||||
|
||||
/* is there a full memory map? */
|
||||
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
|
||||
|
||||
/* Is there drive info? */
|
||||
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
|
||||
|
||||
/* Is there a config table? */
|
||||
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
|
||||
|
||||
/* Is there a boot loader name? */
|
||||
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
|
||||
|
||||
/* Is there a APM table? */
|
||||
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
|
||||
|
||||
/* Is there video information? */
|
||||
#define MULTIBOOT_INFO_VBE_INFO 0x00000800
|
||||
#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000
|
||||
|
||||
#ifndef ASM_FILE
|
||||
|
||||
typedef unsigned char multiboot_uint8_t;
|
||||
typedef unsigned short multiboot_uint16_t;
|
||||
typedef unsigned int multiboot_uint32_t;
|
||||
typedef unsigned long long multiboot_uint64_t;
|
||||
|
||||
struct multiboot_header
|
||||
{
|
||||
/* Must be MULTIBOOT_MAGIC - see above. */
|
||||
multiboot_uint32_t magic;
|
||||
|
||||
/* Feature flags. */
|
||||
multiboot_uint32_t flags;
|
||||
|
||||
/* The above fields plus this one must equal 0 mod 2^32. */
|
||||
multiboot_uint32_t checksum;
|
||||
|
||||
/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */
|
||||
multiboot_uint32_t header_addr;
|
||||
multiboot_uint32_t load_addr;
|
||||
multiboot_uint32_t load_end_addr;
|
||||
multiboot_uint32_t bss_end_addr;
|
||||
multiboot_uint32_t entry_addr;
|
||||
|
||||
/* These are only valid if MULTIBOOT_VIDEO_MODE is set. */
|
||||
multiboot_uint32_t mode_type;
|
||||
multiboot_uint32_t width;
|
||||
multiboot_uint32_t height;
|
||||
multiboot_uint32_t depth;
|
||||
};
|
||||
|
||||
/* The symbol table for a.out. */
|
||||
struct multiboot_aout_symbol_table
|
||||
{
|
||||
multiboot_uint32_t tabsize;
|
||||
multiboot_uint32_t strsize;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t reserved;
|
||||
};
|
||||
typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;
|
||||
|
||||
/* The section header table for ELF. */
|
||||
struct multiboot_elf_section_header_table
|
||||
{
|
||||
multiboot_uint32_t num;
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint32_t addr;
|
||||
multiboot_uint32_t shndx;
|
||||
};
|
||||
typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;
|
||||
|
||||
struct multiboot_info
|
||||
{
|
||||
/* Multiboot info version number */
|
||||
multiboot_uint32_t flags;
|
||||
|
||||
/* Available memory from BIOS */
|
||||
multiboot_uint32_t mem_lower;
|
||||
multiboot_uint32_t mem_upper;
|
||||
|
||||
/* "root" partition */
|
||||
multiboot_uint32_t boot_device;
|
||||
|
||||
/* Kernel command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/* Boot-Module list */
|
||||
multiboot_uint32_t mods_count;
|
||||
multiboot_uint32_t mods_addr;
|
||||
|
||||
union
|
||||
{
|
||||
multiboot_aout_symbol_table_t aout_sym;
|
||||
multiboot_elf_section_header_table_t elf_sec;
|
||||
} u;
|
||||
|
||||
/* Memory Mapping buffer */
|
||||
multiboot_uint32_t mmap_length;
|
||||
multiboot_uint32_t mmap_addr;
|
||||
|
||||
/* Drive Info buffer */
|
||||
multiboot_uint32_t drives_length;
|
||||
multiboot_uint32_t drives_addr;
|
||||
|
||||
/* ROM configuration table */
|
||||
multiboot_uint32_t config_table;
|
||||
|
||||
/* Boot Loader Name */
|
||||
multiboot_uint32_t boot_loader_name;
|
||||
|
||||
/* APM table */
|
||||
multiboot_uint32_t apm_table;
|
||||
|
||||
/* Video */
|
||||
multiboot_uint32_t vbe_control_info;
|
||||
multiboot_uint32_t vbe_mode_info;
|
||||
multiboot_uint16_t vbe_mode;
|
||||
multiboot_uint16_t vbe_interface_seg;
|
||||
multiboot_uint16_t vbe_interface_off;
|
||||
multiboot_uint16_t vbe_interface_len;
|
||||
|
||||
multiboot_uint64_t framebuffer_addr;
|
||||
multiboot_uint32_t framebuffer_pitch;
|
||||
multiboot_uint32_t framebuffer_width;
|
||||
multiboot_uint32_t framebuffer_height;
|
||||
multiboot_uint8_t framebuffer_bpp;
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
|
||||
multiboot_uint8_t framebuffer_type;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
multiboot_uint32_t framebuffer_palette_addr;
|
||||
multiboot_uint16_t framebuffer_palette_num_colors;
|
||||
};
|
||||
struct
|
||||
{
|
||||
multiboot_uint8_t framebuffer_red_field_position;
|
||||
multiboot_uint8_t framebuffer_red_mask_size;
|
||||
multiboot_uint8_t framebuffer_green_field_position;
|
||||
multiboot_uint8_t framebuffer_green_mask_size;
|
||||
multiboot_uint8_t framebuffer_blue_field_position;
|
||||
multiboot_uint8_t framebuffer_blue_mask_size;
|
||||
};
|
||||
};
|
||||
};
|
||||
typedef struct multiboot_info multiboot_info_t;
|
||||
|
||||
struct multiboot_color
|
||||
{
|
||||
multiboot_uint8_t red;
|
||||
multiboot_uint8_t green;
|
||||
multiboot_uint8_t blue;
|
||||
};
|
||||
|
||||
struct multiboot_mmap_entry
|
||||
{
|
||||
multiboot_uint32_t size;
|
||||
multiboot_uint64_t addr;
|
||||
multiboot_uint64_t len;
|
||||
#define MULTIBOOT_MEMORY_AVAILABLE 1
|
||||
#define MULTIBOOT_MEMORY_RESERVED 2
|
||||
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
|
||||
#define MULTIBOOT_MEMORY_NVS 4
|
||||
#define MULTIBOOT_MEMORY_BADRAM 5
|
||||
multiboot_uint32_t type;
|
||||
} __attribute__((packed));
|
||||
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
|
||||
|
||||
struct multiboot_mod_list
|
||||
{
|
||||
/* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */
|
||||
multiboot_uint32_t mod_start;
|
||||
multiboot_uint32_t mod_end;
|
||||
|
||||
/* Module command line */
|
||||
multiboot_uint32_t cmdline;
|
||||
|
||||
/* padding to take it to 16 bytes (must be zero) */
|
||||
multiboot_uint32_t pad;
|
||||
};
|
||||
typedef struct multiboot_mod_list multiboot_module_t;
|
||||
|
||||
/* APM BIOS info. */
|
||||
struct multiboot_apm_info
|
||||
{
|
||||
multiboot_uint16_t version;
|
||||
multiboot_uint16_t cseg;
|
||||
multiboot_uint32_t offset;
|
||||
multiboot_uint16_t cseg_16;
|
||||
multiboot_uint16_t dseg;
|
||||
multiboot_uint16_t flags;
|
||||
multiboot_uint16_t cseg_len;
|
||||
multiboot_uint16_t cseg_16_len;
|
||||
multiboot_uint16_t dseg_len;
|
||||
};
|
||||
|
||||
#endif /* ! ASM_FILE */
|
||||
|
||||
#endif /* ! MULTIBOOT_HEADER */
|
88
src/serial.asm
Normal file
88
src/serial.asm
Normal file
|
@ -0,0 +1,88 @@
|
|||
SERIAL_PORT equ 0x3f8
|
||||
serialinitialized db 0
|
||||
|
||||
serialinit:
|
||||
push ax
|
||||
|
||||
;Disable ints
|
||||
mov dx, SERIAL_PORT+1
|
||||
mov al, 0x00
|
||||
out dx, al
|
||||
|
||||
;Enable DLAB baud divisor and set 3 (38400 baud)
|
||||
mov al, 0x80
|
||||
mov dx, SERIAL_PORT+3
|
||||
out dx, al
|
||||
;Baud divisor lo byte
|
||||
mov al, 0x03
|
||||
mov dx, SERIAL_PORT
|
||||
out dx, al
|
||||
;Baud divisor hi byte
|
||||
mov al, 0x00
|
||||
mov dx, SERIAL_PORT+1
|
||||
out dx, al
|
||||
|
||||
;8bits, no parity, one stop bit
|
||||
mov al, 0x03
|
||||
mov dx, SERIAL_PORT+3
|
||||
out dx, al
|
||||
|
||||
;Enable+clear FIFO, 14-byte threshold
|
||||
mov al, 0xc7
|
||||
mov dx, SERIAL_PORT+2
|
||||
out dx, al
|
||||
|
||||
;IRQs enabled, RTS/DSR set
|
||||
mov al, 0x0b
|
||||
mov dx, SERIAL_PORT+4
|
||||
out dx, al
|
||||
|
||||
;Set loopback for test purposes
|
||||
mov al, 0x1e
|
||||
out dx, al
|
||||
|
||||
;; Check if serial is workie
|
||||
mov al, 0xae
|
||||
mov dx, SERIAL_PORT
|
||||
out dx, al
|
||||
in al, dx
|
||||
cmp al, 0xae
|
||||
jne .end
|
||||
;; Set serial to normal operation
|
||||
mov dx, SERIAL_PORT+4
|
||||
mov al, 0x0f
|
||||
out dx, al
|
||||
mov [serialinitialized], 1
|
||||
.end:
|
||||
pop ax
|
||||
ret
|
||||
.errormsg db "Serial init failed", 0
|
||||
|
||||
serialwrite:
|
||||
cmp [serialinitialized], 0
|
||||
je .notinitialized
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push esi
|
||||
push ax
|
||||
cld
|
||||
mov esi, [ebp+8]
|
||||
.loop:
|
||||
mov dx, SERIAL_PORT+5
|
||||
.wait:
|
||||
in al, dx
|
||||
and al, 0x20
|
||||
jz .wait
|
||||
lodsb
|
||||
or al, al
|
||||
jz .done
|
||||
mov dx, SERIAL_PORT
|
||||
out dx, al
|
||||
jmp .loop
|
||||
.done:
|
||||
pop ax
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
.notinitialized:
|
||||
ret
|
49
src/serial.c
49
src/serial.c
|
@ -1,49 +0,0 @@
|
|||
#include "serial.h"
|
||||
#define PORT 0x3f8 // COM1
|
||||
|
||||
static inline void outb(unsigned short port, unsigned char val) {
|
||||
asm volatile ("outb %0, %1" : : "a"(val), "Nd"(port) : "memory");
|
||||
}
|
||||
static inline unsigned char inb(unsigned short port) {
|
||||
unsigned char ret;
|
||||
asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int serial_init() {
|
||||
outb(PORT + 1, 0x00); // Disable all interrupts
|
||||
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
|
||||
outb(PORT + 1, 0x00); // (hi byte)
|
||||
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip
|
||||
outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial
|
||||
// returns same byte)
|
||||
|
||||
// Check if serial is faulty (i.e: not same byte as sent)
|
||||
if (inb(PORT + 0) != 0xAE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If serial is not faulty set it in normal operation mode
|
||||
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
|
||||
outb(PORT + 4, 0x0F);
|
||||
return 0;
|
||||
}
|
||||
static int serial_is_transmit_empty() { return inb(PORT + 5) & 0x20; }
|
||||
|
||||
static void serial_write_char(char chr) {
|
||||
while (serial_is_transmit_empty() == 0);
|
||||
outb(PORT, chr);
|
||||
}
|
||||
|
||||
void serial_write_string(const char* text) {
|
||||
int i = 0;
|
||||
while(text[i]) {
|
||||
serial_write_char(text[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#ifndef HEADER_SERIAL
|
||||
#define HEADER_SERIAL
|
||||
|
||||
int serial_init(void);
|
||||
void serial_write_string(const char* text);
|
||||
|
||||
#endif
|
175
src/start32.asm
175
src/start32.asm
|
@ -1,47 +1,166 @@
|
|||
format binary
|
||||
use32
|
||||
org 0x100000
|
||||
|
||||
MULTIBOOT_HEADER_MAGIC equ 0x1BADB002
|
||||
MULTIBOOT_PAGE_ALIGN equ 1 << 0
|
||||
MULTIBOOT_MEMORY_INFO equ 1 << 1
|
||||
MULTIBOOT_VIDEO_REQUEST equ 0 << 2
|
||||
MULTIBOOT_AOUT_KLUDGE equ 0 << 16
|
||||
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_REQUEST
|
||||
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_REQUEST | MULTIBOOT_AOUT_KLUDGE
|
||||
MULTIBOOT_PAGE_ALIGN equ (1 shl 0)
|
||||
MULTIBOOT_MEMORY_INFO equ (1 shl 1)
|
||||
MULTIBOOT_VIDEO_REQUEST equ (1 shl 2)
|
||||
MULTIBOOT_AOUT_KLUDGE equ (1 shl 16)
|
||||
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN or MULTIBOOT_MEMORY_INFO or MULTIBOOT_VIDEO_REQUEST
|
||||
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN or MULTIBOOT_MEMORY_INFO or MULTIBOOT_VIDEO_REQUEST or MULTIBOOT_AOUT_KLUDGE
|
||||
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
|
||||
|
||||
section .multiboot
|
||||
align 4
|
||||
multiboot:
|
||||
dd MULTIBOOT_HEADER_MAGIC
|
||||
dd MULTIBOOT_HEADER_FLAGS
|
||||
dd MULTIBOOT_CHECKSUM
|
||||
dd 0 ; header address
|
||||
dd 0 ; load address
|
||||
dd 0 ; load end address
|
||||
dd 0 ; bss end address
|
||||
dd 0 ; entry address
|
||||
dd multiboot ; header address
|
||||
dd 0x100000 ; load address
|
||||
dd bss ; load end address
|
||||
dd stack_top ; bss end address
|
||||
dd start ; entry address
|
||||
dd 0 ; video mode_type (0:fb, 1:txt) (set flags[2]!)
|
||||
dd 1024 ; video width
|
||||
dd 768 ; video height
|
||||
dd 32 ; video depth
|
||||
|
||||
section .bss
|
||||
align 16
|
||||
stack_bottom:
|
||||
resb 16384
|
||||
stack_top:
|
||||
|
||||
section .text
|
||||
global _start
|
||||
extern kmain
|
||||
|
||||
_start:
|
||||
start:
|
||||
; Setup stack
|
||||
mov ebp, stack_top
|
||||
mov esp, stack_top
|
||||
|
||||
; Call the main kernel function.
|
||||
push ebx
|
||||
push eax
|
||||
call kmain
|
||||
|
||||
.hang:
|
||||
call serialinit
|
||||
push stuff.bootmsg
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
|
||||
call mbootgetinfo
|
||||
add esp, 2*4
|
||||
|
||||
mov eax, [mbootinfo.fb_addr]
|
||||
mov dword [eax], 0xffffffff
|
||||
|
||||
|
||||
push stuff.fbaddrmsgpfx
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
|
||||
sub esp, 36 ;Reserve stack for return
|
||||
push dword esp ;Destination address
|
||||
push dword 16 ;Base
|
||||
push dword [mbootinfo.fb_addr] ;source
|
||||
call __uitoa
|
||||
add esp, 3*4
|
||||
push esp
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
|
||||
push stuff.fbdimensionsmsgpfx
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
push dword esp ;destination address
|
||||
push dword 10 ;base
|
||||
push dword [mbootinfo.fb_width]
|
||||
call __uitoa
|
||||
add esp, 3*4
|
||||
push esp
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
push stuff.x
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
|
||||
push dword esp ;destination address
|
||||
push dword 10 ;base
|
||||
push dword [mbootinfo.fb_height]
|
||||
call __uitoa
|
||||
add esp, 3*4
|
||||
push esp
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
push stuff.x
|
||||
call serialwrite
|
||||
|
||||
add esp, 4
|
||||
push dword esp ;destination address
|
||||
push dword 10 ;base
|
||||
xor eax, eax
|
||||
mov al, [mbootinfo.fb_bpp]
|
||||
push dword eax
|
||||
call __uitoa
|
||||
add esp, 3*4
|
||||
push esp
|
||||
call serialwrite
|
||||
add esp, 4
|
||||
|
||||
add esp, 36 ;Clean reserved uitoa return string from stack
|
||||
|
||||
|
||||
;; Setup paging
|
||||
;; Clear pagedir
|
||||
cld
|
||||
mov eax, 0x00000002 ;Supervisor only, Write enabled, Not present
|
||||
mov ecx, 1024
|
||||
mov edi, pagedir
|
||||
rep stosd
|
||||
|
||||
;; Clear pagetable1
|
||||
mov edi, pagetable1
|
||||
mov cx, 0
|
||||
.clearpt1loop:
|
||||
mov eax, 0x00001000
|
||||
mul ecx
|
||||
or eax, 011b ;supervisor, rw, present
|
||||
stosd
|
||||
inc cx
|
||||
cmp cx, 1024
|
||||
jne .clearpt1loop
|
||||
|
||||
;; put table1 in dir
|
||||
mov eax, pagetable1
|
||||
or eax, 011b ;supervisor, rw, present
|
||||
mov [pagedir], eax
|
||||
|
||||
;; Enable paging
|
||||
mov eax, pagedir
|
||||
mov cr3, eax
|
||||
mov eax, cr0
|
||||
or eax, 0x80000000
|
||||
mov cr0, eax
|
||||
|
||||
jmp hang
|
||||
|
||||
hang:
|
||||
push .msg
|
||||
call serialwrite
|
||||
cli
|
||||
.loop:
|
||||
hlt
|
||||
jmp .hang
|
||||
jmp .loop
|
||||
.msg db 10, "Halting...", 10, 0
|
||||
|
||||
include "src/serial.asm"
|
||||
include "src/mbootinfo.asm"
|
||||
include "src/itoa.asm"
|
||||
|
||||
stuff:
|
||||
.bootmsg db 10, "=== KoalemOS ===", 10, 0
|
||||
.fbaddrmsgpfx db 10, "Framebuffer address: 0x", 0
|
||||
.fbdimensionsmsgpfx db 10, "Framebuffer dimensions: ", 0
|
||||
.x db "x", 0
|
||||
|
||||
bss:
|
||||
align 4096
|
||||
pagedir:
|
||||
rb 4096
|
||||
align 4096
|
||||
pagetable1:
|
||||
rb 4096
|
||||
align 4096
|
||||
stack_bottom:
|
||||
rb 16384
|
||||
stack_top:
|
||||
|
|
97
src/vga.c
97
src/vga.c
|
@ -1,97 +0,0 @@
|
|||
#include "vga.h"
|
||||
#define VGA_WIDTH 80
|
||||
#define VGA_HEIGHT 25
|
||||
#define VGA_MEM_ADDR 0xb8000
|
||||
#define CURSOR_HOME (VGA_HEIGHT-1)*VGA_WIDTH
|
||||
#define CURSOR_CHR 177;
|
||||
|
||||
unsigned int cursor_loc = CURSOR_HOME;
|
||||
unsigned char fgcolor;
|
||||
unsigned char bgcolor;
|
||||
unsigned short blank;
|
||||
|
||||
static unsigned char vga_entry_color(enum vga_color fg, enum vga_color bg) {
|
||||
return fg | bg << 4;
|
||||
}
|
||||
unsigned short vga_blank_entry() {
|
||||
return vga_entry_color(fgcolor, bgcolor) << 8;
|
||||
}
|
||||
void draw_cursor(void) {
|
||||
*((unsigned char *)VGA_MEM_ADDR + cursor_loc * 2) = CURSOR_CHR;
|
||||
*((unsigned char *)VGA_MEM_ADDR+1 + cursor_loc * 2) = vga_entry_color(fgcolor, bgcolor);
|
||||
}
|
||||
|
||||
void vga_set_color(enum vga_color fg, enum vga_color bg) {
|
||||
fgcolor = fg;
|
||||
bgcolor = bg;
|
||||
}
|
||||
void vga_init(enum vga_color fg, enum vga_color bg) {
|
||||
vga_set_color(fg, bg);
|
||||
blank = vga_blank_entry();
|
||||
cls();
|
||||
}
|
||||
void cls(void) {
|
||||
int i;
|
||||
for (i=0; i<VGA_HEIGHT*VGA_WIDTH;i++) {
|
||||
*((unsigned short *) VGA_MEM_ADDR+i) = blank;
|
||||
}
|
||||
}
|
||||
void scroll(void) {
|
||||
int y;
|
||||
int x;
|
||||
*((unsigned short *) VGA_MEM_ADDR+cursor_loc) = blank;
|
||||
for (y=0;y<VGA_HEIGHT;y++) {
|
||||
for (x = 0;x<VGA_WIDTH;x++) {
|
||||
*((unsigned short *) VGA_MEM_ADDR+y*VGA_WIDTH+x) = *((unsigned short *) VGA_MEM_ADDR+(y+1)*VGA_WIDTH+x);
|
||||
}
|
||||
}
|
||||
for (x=0;x<VGA_WIDTH;x++) {
|
||||
*((unsigned short *) VGA_MEM_ADDR+CURSOR_HOME+x) = blank;
|
||||
}
|
||||
cursor_loc = CURSOR_HOME;
|
||||
draw_cursor();
|
||||
}
|
||||
void putchar(unsigned char chr) {
|
||||
if (chr == '\n') {
|
||||
scroll();
|
||||
return;
|
||||
}
|
||||
*((unsigned char *) VGA_MEM_ADDR+cursor_loc * 2) = chr;
|
||||
*((unsigned char *) VGA_MEM_ADDR+1+cursor_loc * 2) = vga_entry_color(fgcolor, bgcolor);
|
||||
cursor_loc++;
|
||||
if (cursor_loc >= VGA_HEIGHT*VGA_WIDTH) {
|
||||
scroll();
|
||||
}
|
||||
draw_cursor();
|
||||
}
|
||||
|
||||
void vga_write(const char* text) {
|
||||
int i = 0;
|
||||
while(text[i]) {
|
||||
putchar(text[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
void vga_write_color( const char* text, enum vga_color fg, enum vga_color bg) {
|
||||
unsigned char prevfg = fgcolor;
|
||||
unsigned char prevbg = bgcolor;
|
||||
vga_set_color(fg, bg);
|
||||
vga_write(text);
|
||||
fgcolor = prevfg;
|
||||
bgcolor = prevbg;
|
||||
}
|
||||
void vga_write_line(const char* text) {
|
||||
if (cursor_loc != CURSOR_HOME) {
|
||||
scroll();
|
||||
}
|
||||
vga_write(text);
|
||||
scroll();
|
||||
}
|
||||
void vga_write_line_color(const char* text, enum vga_color fg, enum vga_color bg) {
|
||||
unsigned char prevfg = fgcolor;
|
||||
unsigned char prevbg = bgcolor;
|
||||
vga_set_color(fg, bg);
|
||||
vga_write_line(text);
|
||||
fgcolor = prevfg;
|
||||
bgcolor = prevbg;
|
||||
}
|
24
src/vga.h
24
src/vga.h
|
@ -1,24 +0,0 @@
|
|||
#ifndef HEADER_VGA
|
||||
#define HEADER_VGA
|
||||
|
||||
enum vga_color {
|
||||
VGA_COLOR_BLACK = 0,
|
||||
VGA_COLOR_BLUE = 1,
|
||||
VGA_COLOR_GREEN = 2,
|
||||
VGA_COLOR_CYAN = 3,
|
||||
VGA_COLOR_RED = 4,
|
||||
VGA_COLOR_MAGENTA = 5,
|
||||
VGA_COLOR_ORANGE = 6,
|
||||
VGA_COLOR_GREY = 7,
|
||||
VGA_COLOR_GRAY = 7,
|
||||
};
|
||||
|
||||
void cls(void);
|
||||
void vga_init(enum vga_color fg, enum vga_color bg);
|
||||
|
||||
void vga_write(const char* text);
|
||||
void vga_write_color( const char* text, enum vga_color fg, enum vga_color bg);
|
||||
void vga_write_line(const char* text);
|
||||
void vga_write_line_color( const char* text, enum vga_color fg, enum vga_color bg);
|
||||
|
||||
#endif
|
100
src/xtoa.c
100
src/xtoa.c
|
@ -1,100 +0,0 @@
|
|||
#include "xtoa.h"
|
||||
char* itoa(int value, int base) {
|
||||
char* result;
|
||||
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
// Apply negative sign
|
||||
if (tmp_value < 0) *ptr++ = '-';
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
char* uitoa(unsigned int value, int base) {
|
||||
char* result;
|
||||
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
char* ltoa(long value, int base) {
|
||||
char* result;
|
||||
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
// Apply negative sign
|
||||
if (tmp_value < 0) *ptr++ = '-';
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
char* ultoa(unsigned long value, int base) {
|
||||
char* result;
|
||||
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
// Apply negative sign
|
||||
//if (tmp_value < 0) *ptr++ = '-';
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef HEADER_XTOA
|
||||
#define HEADER_XTOA
|
||||
|
||||
char* itoa(int value, int base);
|
||||
char* uitoa(unsigned int value, int base);
|
||||
char* ltoa(long value, int base);
|
||||
char* ultoa(unsigned long value, int base);
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue