dead@root user mode fail
This commit is contained in:
parent
208a80104f
commit
c355d80244
2
Makefile
2
Makefile
@ -10,7 +10,7 @@ KERNEL = deados.bin
|
|||||||
ISO = deados.iso
|
ISO = deados.iso
|
||||||
|
|
||||||
SOURCES_C = kernel.c tty.c idt.c timer.c io.c vga.c gdt.c sys.c irq.c isr.c keyboard.c shell.c string.c user_space.c syscall.c
|
SOURCES_C = kernel.c tty.c idt.c timer.c io.c vga.c gdt.c sys.c irq.c isr.c keyboard.c shell.c string.c user_space.c syscall.c
|
||||||
SOURCES_ASM = boot.s idt_load.s gdt_flush.s pit_handler.s irq_e.s isr_e.s
|
SOURCES_ASM = boot.s idt_load.s gdt_flush.s pit_handler.s irq_e.s isr_e.s tss.s
|
||||||
OBJECTS = $(SOURCES_ASM:.s=.o) $(SOURCES_C:.c=.o)
|
OBJECTS = $(SOURCES_ASM:.s=.o) $(SOURCES_C:.c=.o)
|
||||||
|
|
||||||
ISO_DIR = isodir
|
ISO_DIR = isodir
|
||||||
|
66
gdt.c
66
gdt.c
@ -1,29 +1,69 @@
|
|||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
struct gdt_entry gdt[3];
|
#define GDT_ENTRY 6
|
||||||
struct gdt_ptr gdtp;
|
|
||||||
|
Gdt_entry gdt[GDT_ENTRY];
|
||||||
|
Gdt_ptr gdtp;
|
||||||
|
|
||||||
extern void gdt_flush(uint32_t);
|
extern void gdt_flush(uint32_t);
|
||||||
|
|
||||||
void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
|
Tss_entry tss;
|
||||||
gdt[num].base_low = (base & 0xFFFF);
|
extern void tss_flush(void);
|
||||||
|
|
||||||
|
static void gdt_set_gate(uint8_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity)
|
||||||
|
{
|
||||||
|
gdt[num].base_low = base & 0xFFFF;
|
||||||
gdt[num].base_middle = (base >> 16) & 0xFF;
|
gdt[num].base_middle = (base >> 16) & 0xFF;
|
||||||
gdt[num].base_high = (base >> 24) & 0xFF;
|
gdt[num].base_high = (base >> 24) & 0xFF;
|
||||||
|
|
||||||
gdt[num].limit_low = (limit & 0xFFFF);
|
gdt[num].limit_low = limit & 0xFFFF;
|
||||||
gdt[num].granularity = (limit >> 16) & 0x0F;
|
|
||||||
|
gdt[num].granularity = (limit >> 16) & 0xF;
|
||||||
|
gdt[num].granularity |= (granularity & 0xF0);
|
||||||
|
|
||||||
gdt[num].granularity |= gran & 0xF0;
|
|
||||||
gdt[num].access = access;
|
gdt[num].access = access;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdt_install() {
|
static void tss_install(uint8_t num, uint16_t kernel_ss, uint16_t kernel_esp)
|
||||||
gdtp.limit = (sizeof(struct gdt_entry) * 3) - 1;
|
{
|
||||||
|
uint32_t base = (uint32_t)&tss;
|
||||||
|
uint32_t limit = base + sizeof(Tss_entry);
|
||||||
|
|
||||||
|
gdt_set_gate(num, base, limit, 0xE9, 0x0);
|
||||||
|
|
||||||
|
memset(&tss, 0, sizeof(Tss_entry));
|
||||||
|
|
||||||
|
tss.ss0 = kernel_ss;
|
||||||
|
tss.esp0 = kernel_esp;
|
||||||
|
|
||||||
|
tss.cs = 0x0B;
|
||||||
|
tss.ss = 0x13;
|
||||||
|
tss.es = 0x13;
|
||||||
|
tss.ds = 0x13;
|
||||||
|
tss.fs = 0x13;
|
||||||
|
tss.gs = 0x13;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_kernel_stack(uint32_t stack)
|
||||||
|
{
|
||||||
|
tss.esp0 = stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gdt_install()
|
||||||
|
{
|
||||||
|
|
||||||
|
gdt_set_gate(0, 0x0, 0x0, 0x0, 0x0); // Null segment
|
||||||
|
gdt_set_gate(1, 0x0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel code segment
|
||||||
|
gdt_set_gate(2, 0x0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
|
||||||
|
gdt_set_gate(3, 0x0, 0xFFFFFFFF, 0xFA, 0xCF); // User code segment
|
||||||
|
gdt_set_gate(4, 0x0, 0xFFFFFFFF, 0xF2, 0xCF); // User data segment
|
||||||
|
|
||||||
|
tss_install(5, 0x10, 0x0);
|
||||||
|
|
||||||
|
gdtp.limit = (sizeof(Gdt_entry) * GDT_ENTRY) - 1;
|
||||||
gdtp.base = (uint32_t)&gdt;
|
gdtp.base = (uint32_t)&gdt;
|
||||||
|
|
||||||
gdt_set_gate(0, 0, 0, 0, 0); // Null segment
|
|
||||||
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
|
|
||||||
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
|
|
||||||
|
|
||||||
gdt_flush((uint32_t)&gdtp);
|
gdt_flush((uint32_t)&gdtp);
|
||||||
|
tss_flush();
|
||||||
}
|
}
|
||||||
|
47
gdt.h
47
gdt.h
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct gdt_entry {
|
typedef struct gdt_entry_t Gdt_entry;
|
||||||
|
struct gdt_entry_t
|
||||||
|
{
|
||||||
uint16_t limit_low;
|
uint16_t limit_low;
|
||||||
uint16_t base_low;
|
uint16_t base_low;
|
||||||
uint8_t base_middle;
|
uint8_t base_middle;
|
||||||
@ -12,15 +14,48 @@ struct gdt_entry {
|
|||||||
uint8_t base_high;
|
uint8_t base_high;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct gdt_ptr {
|
typedef struct gdt_ptr_t Gdt_ptr;
|
||||||
|
struct gdt_ptr_t
|
||||||
|
{
|
||||||
uint16_t limit;
|
uint16_t limit;
|
||||||
uint32_t base;
|
uint32_t base;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
extern struct gdt_entry gdt[3];
|
static void gdt_set_gate(uint8_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity);
|
||||||
extern struct gdt_ptr gdtp;
|
|
||||||
|
|
||||||
void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran);
|
|
||||||
void gdt_install();
|
void gdt_install();
|
||||||
|
|
||||||
|
void set_kernel_stack(uint32_t stack);
|
||||||
|
|
||||||
|
typedef struct tss_entry_t Tss_entry;
|
||||||
|
struct tss_entry_t
|
||||||
|
{
|
||||||
|
uint32_t prevTss;
|
||||||
|
uint32_t esp0;
|
||||||
|
uint32_t ss0;
|
||||||
|
uint32_t esp1;
|
||||||
|
uint32_t ss1;
|
||||||
|
uint32_t esp2;
|
||||||
|
uint32_t ss2;
|
||||||
|
uint32_t cr3;
|
||||||
|
uint32_t eip;
|
||||||
|
uint32_t eflags;
|
||||||
|
uint32_t eax;
|
||||||
|
uint32_t ecx;
|
||||||
|
uint32_t edx;
|
||||||
|
uint32_t ebx;
|
||||||
|
uint32_t esp;
|
||||||
|
uint32_t ebp;
|
||||||
|
uint32_t esi;
|
||||||
|
uint32_t edi;
|
||||||
|
uint32_t es;
|
||||||
|
uint32_t cs;
|
||||||
|
uint32_t ss;
|
||||||
|
uint32_t ds;
|
||||||
|
uint32_t fs;
|
||||||
|
uint32_t gs;
|
||||||
|
uint32_t ldt;
|
||||||
|
uint16_t trap;
|
||||||
|
uint16_t iomap;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
#endif
|
#endif
|
3
grub.cfg
3
grub.cfg
@ -1,3 +1,6 @@
|
|||||||
|
default=0
|
||||||
|
timeout=0
|
||||||
|
|
||||||
menuentry "deadOS" {
|
menuentry "deadOS" {
|
||||||
multiboot /boot/deados.bin
|
multiboot /boot/deados.bin
|
||||||
}
|
}
|
36
idt.c
36
idt.c
@ -1,10 +1,12 @@
|
|||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "string.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define IDT_ENTRIES 256
|
#define IDT_ENTRIES 256
|
||||||
|
|
||||||
struct idt_entry {
|
struct idt_entry
|
||||||
|
{
|
||||||
uint16_t base_lo;
|
uint16_t base_lo;
|
||||||
uint16_t sel;
|
uint16_t sel;
|
||||||
uint8_t always0;
|
uint8_t always0;
|
||||||
@ -12,7 +14,8 @@ struct idt_entry {
|
|||||||
uint16_t base_hi;
|
uint16_t base_hi;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct idt_ptr {
|
struct idt_ptr
|
||||||
|
{
|
||||||
uint16_t limit;
|
uint16_t limit;
|
||||||
uint32_t base;
|
uint32_t base;
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
@ -20,7 +23,8 @@ struct idt_ptr {
|
|||||||
struct idt_entry idt[IDT_ENTRIES];
|
struct idt_entry idt[IDT_ENTRIES];
|
||||||
struct idt_ptr idtp;
|
struct idt_ptr idtp;
|
||||||
|
|
||||||
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
|
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
|
||||||
|
{
|
||||||
idt[num].base_lo = base & 0xFFFF;
|
idt[num].base_lo = base & 0xFFFF;
|
||||||
idt[num].base_hi = (base >> 16) & 0xFFFF;
|
idt[num].base_hi = (base >> 16) & 0xFFFF;
|
||||||
idt[num].sel = sel;
|
idt[num].sel = sel;
|
||||||
@ -28,28 +32,12 @@ void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
|
|||||||
idt[num].flags = flags | 0x60;
|
idt[num].flags = flags | 0x60;
|
||||||
}
|
}
|
||||||
|
|
||||||
void idt_install() {
|
void idt_install()
|
||||||
|
{
|
||||||
idtp.limit = (sizeof(struct idt_entry) * IDT_ENTRIES) - 1;
|
idtp.limit = (sizeof(struct idt_entry) * IDT_ENTRIES) - 1;
|
||||||
idtp.base = (uint32_t)&idt;
|
idtp.base = (uint32_t)&idt;
|
||||||
|
|
||||||
|
memset(&idt, 0, sizeof(struct idt_entry) * IDT_ENTRIES);
|
||||||
|
|
||||||
idt_load();
|
idt_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pic_remap(int offset1, int offset2) {
|
|
||||||
unsigned char a1, a2;
|
|
||||||
|
|
||||||
a1 = inb(0x21);
|
|
||||||
a2 = inb(0xA1);
|
|
||||||
|
|
||||||
outb(0x20, 0x11);
|
|
||||||
outb(0xA0, 0x11);
|
|
||||||
outb(0x21, offset1);
|
|
||||||
outb(0xA1, offset2);
|
|
||||||
outb(0x21, 0x04);
|
|
||||||
outb(0xA1, 0x02);
|
|
||||||
|
|
||||||
outb(0x21, 0x01);
|
|
||||||
outb(0xA1, 0x01);
|
|
||||||
|
|
||||||
outb(0x21, a1);
|
|
||||||
outb(0xA1, a2);
|
|
||||||
}
|
|
11
kernel.c
11
kernel.c
@ -18,7 +18,6 @@ void kernel_main(void)
|
|||||||
gdt_install();
|
gdt_install();
|
||||||
|
|
||||||
idt_install();
|
idt_install();
|
||||||
|
|
||||||
isr_install();
|
isr_install();
|
||||||
irq_install();
|
irq_install();
|
||||||
|
|
||||||
@ -26,20 +25,18 @@ void kernel_main(void)
|
|||||||
|
|
||||||
keyboard_install();
|
keyboard_install();
|
||||||
|
|
||||||
sys_enable_interrupts();
|
terminal_printc("Welcome to &cDeadOS&7.\n");
|
||||||
|
|
||||||
terminal_printc("Hello, &ekernel &7World!\n&5Magenta String Example\nThis is a &4red string&7.\n");
|
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
terminal_printc("&cDead &7");
|
terminal_printc("&cDead &7");
|
||||||
terminal_putchar('0' + (i / 10));
|
terminal_putchar('0' + (i / 10));
|
||||||
terminal_putchar('0' + (i % 10));
|
terminal_putchar('0' + (i % 10));
|
||||||
terminal_printc("\n");
|
terminal_printc("\n");
|
||||||
delay(500);
|
delay(100);
|
||||||
}
|
}
|
||||||
// syscall_init();
|
syscall_init();
|
||||||
|
|
||||||
// enter_user_space();
|
enter_user_space();
|
||||||
|
|
||||||
shell_init();
|
shell_init();
|
||||||
}
|
}
|
4
shell.c
4
shell.c
@ -80,7 +80,7 @@ void shell_echo_command(char *input)
|
|||||||
void shell_parse_input(char *input)
|
void shell_parse_input(char *input)
|
||||||
{
|
{
|
||||||
char *command = strtok(input, " \n");
|
char *command = strtok(input, " \n");
|
||||||
char *first_param = strtok(NULL, " \n");
|
char *args = input + strlen(command) + 1;
|
||||||
|
|
||||||
if (command == NULL || *command == '\0')
|
if (command == NULL || *command == '\0')
|
||||||
{
|
{
|
||||||
@ -93,7 +93,7 @@ void shell_parse_input(char *input)
|
|||||||
}
|
}
|
||||||
else if (strcmp(command, "echo") == 0)
|
else if (strcmp(command, "echo") == 0)
|
||||||
{
|
{
|
||||||
shell_echo_command(first_param);
|
shell_echo_command(args);
|
||||||
}
|
}
|
||||||
else if (strcmp(command, "exit") == 0)
|
else if (strcmp(command, "exit") == 0)
|
||||||
{
|
{
|
||||||
|
36
string.c
36
string.c
@ -1,6 +1,26 @@
|
|||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
size_t strlen(const char *str)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (str[len])
|
||||||
|
++len;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memset(void *ptr, int value, size_t size)
|
||||||
|
{
|
||||||
|
unsigned char *buf = (unsigned char *)ptr;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
buf[i] = (unsigned char)value;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
int strcmp(const char *str1, const char *str2)
|
int strcmp(const char *str1, const char *str2)
|
||||||
{
|
{
|
||||||
while (*str1 && (*str1 == *str2))
|
while (*str1 && (*str1 == *str2))
|
||||||
@ -11,17 +31,17 @@ int strcmp(const char *str1, const char *str2)
|
|||||||
return *(const unsigned char *)str1 - *(const unsigned char *)str2;
|
return *(const unsigned char *)str1 - *(const unsigned char *)str2;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strchr(const char *str, int c)
|
char *strchr(const char *str, int character)
|
||||||
{
|
{
|
||||||
while (*str != '\0')
|
size_t i = 0;
|
||||||
|
while (str[i] != (char)character)
|
||||||
{
|
{
|
||||||
if (*str == c)
|
if (str[i] == '\0')
|
||||||
{
|
return NULL;
|
||||||
return (char *)str;
|
++i;
|
||||||
}
|
|
||||||
str++;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
|
return (char *)(str + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *strtok(char *str, const char *delim)
|
char *strtok(char *str, const char *delim)
|
||||||
|
5
string.h
5
string.h
@ -1,8 +1,13 @@
|
|||||||
#ifndef STRING_H
|
#ifndef STRING_H
|
||||||
#define STRING_H
|
#define STRING_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
char *strchr(const char *str, int c);
|
char *strchr(const char *str, int c);
|
||||||
char *strtok(char *str, const char *delim);
|
char *strtok(char *str, const char *delim);
|
||||||
int strcmp(const char *str1, const char *str2);
|
int strcmp(const char *str1, const char *str2);
|
||||||
|
size_t strlen(const char *str);
|
||||||
|
|
||||||
|
void *memset(void *ptr, int value, size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
44
syscall.c
44
syscall.c
@ -1,23 +1,51 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
#include "sys.h"
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
void test_syscall()
|
#define NB_SYSCALL 8
|
||||||
{
|
|
||||||
terminal_printc("Test syscall called\n");
|
void *syscalls[NB_SYSCALL] = {
|
||||||
}
|
terminal_writestring,
|
||||||
|
keyboard_getchar,
|
||||||
|
terminal_printc,
|
||||||
|
terminal_clear,
|
||||||
|
terminal_putchar,
|
||||||
|
terminal_putentryat,
|
||||||
|
keyboard_clear_buffer,
|
||||||
|
|
||||||
|
sys_halt};
|
||||||
|
|
||||||
void syscall_handler(Stack *registers)
|
void syscall_handler(Stack *registers)
|
||||||
{
|
{
|
||||||
|
terminal_writestring("Syscall\n");
|
||||||
|
|
||||||
int sys_index = registers->eax;
|
int sys_index = registers->eax;
|
||||||
|
|
||||||
if (sys_index != 0)
|
if (sys_index >= NB_SYSCALL)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
test_syscall();
|
void *function = syscalls[sys_index];
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
asm volatile(" push %1; \
|
||||||
|
push %2; \
|
||||||
|
push %3; \
|
||||||
|
push %4; \
|
||||||
|
push %5; \
|
||||||
|
call *%6; \
|
||||||
|
pop %%ebx; \
|
||||||
|
pop %%ebx; \
|
||||||
|
pop %%ebx; \
|
||||||
|
pop %%ebx; \
|
||||||
|
pop %%ebx; \
|
||||||
|
" : "=a"(ret) : "r"(registers->edi), "r"(registers->esi),
|
||||||
|
"r"(registers->edx), "r"(registers->ecx),
|
||||||
|
"r"(registers->ebx), "r"(function));
|
||||||
|
registers->eax = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syscall_init(void)
|
void syscall_init(void)
|
||||||
|
21
timer.c
21
timer.c
@ -15,6 +15,27 @@ void pit_handler()
|
|||||||
outb(0x20, 0x20);
|
outb(0x20, 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pic_remap(int offset1, int offset2)
|
||||||
|
{
|
||||||
|
unsigned char a1, a2;
|
||||||
|
|
||||||
|
a1 = inb(0x21);
|
||||||
|
a2 = inb(0xA1);
|
||||||
|
|
||||||
|
outb(0x20, 0x11);
|
||||||
|
outb(0xA0, 0x11);
|
||||||
|
outb(0x21, offset1);
|
||||||
|
outb(0xA1, offset2);
|
||||||
|
outb(0x21, 0x04);
|
||||||
|
outb(0xA1, 0x02);
|
||||||
|
|
||||||
|
outb(0x21, 0x01);
|
||||||
|
outb(0xA1, 0x01);
|
||||||
|
|
||||||
|
outb(0x21, a1);
|
||||||
|
outb(0xA1, a2);
|
||||||
|
}
|
||||||
|
|
||||||
void delay(uint32_t milliseconds)
|
void delay(uint32_t milliseconds)
|
||||||
{
|
{
|
||||||
uint32_t end = tick + milliseconds;
|
uint32_t end = tick + milliseconds;
|
||||||
|
9
tss.s
Normal file
9
tss.s
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.section .text
|
||||||
|
.align 4
|
||||||
|
|
||||||
|
.global tss_flush
|
||||||
|
.type tss_flush, @function
|
||||||
|
tss_flush:
|
||||||
|
mov $0x2B, %ax
|
||||||
|
ltr %ax
|
||||||
|
ret
|
9
tty.c
9
tty.c
@ -4,14 +4,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "string.h"
|
||||||
size_t strlen(const char *str)
|
|
||||||
{
|
|
||||||
size_t len = 0;
|
|
||||||
while (str[len])
|
|
||||||
len++;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const size_t VGA_WIDTH = 80;
|
static const size_t VGA_WIDTH = 80;
|
||||||
static const size_t VGA_HEIGHT = 25;
|
static const size_t VGA_HEIGHT = 25;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include "user_space.h"
|
#include "user_space.h"
|
||||||
|
#include "gdt.h"
|
||||||
|
|
||||||
void enter_user_space(void)
|
void enter_user_space(void)
|
||||||
{
|
{
|
||||||
asm volatile(" cli; \
|
set_kernel_stack(0x110); // 128KB ?? WHY? ??
|
||||||
|
asm volatile("cli; \
|
||||||
mov $0x23, %ax; \
|
mov $0x23, %ax; \
|
||||||
mov %ax, %ds; \
|
mov %ax, %ds; \
|
||||||
mov %ax, %es; \
|
mov %ax, %es; \
|
||||||
|
Loading…
Reference in New Issue
Block a user