getvect function is undefined - c

I am trying to run this program. It uses the interrupts and when we press w, it replace it by s in keyboard buffer
#include "stdafx.h"
#include "stdio.h"
#include "bios.h"
#include <dos.h>
void interrupt_oldint15(*oldint15);
void interrupt_newint15(unsigned int BP, unsigned int DI, unsigned int SI, unsigned int DS,
unsigned int ES, unsigned int DX, unsigned int CX, unsigned int BX,
unsigned int AX, unsigned int IP, unsigned int CS, unsigned int flags);
void main ( )
{
oldint15 = getvect (0x15);
setvect (0x15, newint15);
keep (0, 1000);
}
void interrupt_newint15 (unsigned int BP, unsigned int DI, unsigned int SI, unsigned int DS, unsigned int ES, unsigned int DX, unsigned int CX, unsigned int BX, unsigned int AX, unsigned int IP, unsigned int CS, unsigned int flags )
{
if(*((char*)&AX)==0x11)
*((char*)&AX)=0x1F;
else if(*((char*)&AX)==0x1F)
*((char*)&AX)=0x11;
}
but it gives the error in getvect and setvect functions.

for one thing, interrupt functions, in C, do not have parameters, nor a returned value.
Listing all the registers is a waste of space (besides which it should not compile) as the entry into a interrupt event causes a saving of all the key registers (typically on the stack of the currently running process)
All the key registers (like the PC and Status registers) are restored upon exit from the interrupt.
The compiler will cause any general purpose registers changed in the interrupt function to be saved/restored.) If you are working at such a low level, then you should know exactly where the interrupt vectors are located, you should have a code segment that overlays the interrupt vectors and another code segment that mirrors the interrupt vectors.
Then, you copy the current set of interrupt vectors to the mirror and then replace the desired individual vector with a pointer to the interrupt function you wrote. At the end of your code, you need to copy the vector back into the original vector area.
It could be that functions you are having trouble with do those operations for you.
this, from a very old post, from a c.comp news group may be helpful:
You are mixing languages. In Borland C an "interrupt" has type
void (interrupt*)()
while in Borland C++ it has type
void (interrupt*)(...)
This affects the parameter type of setvect and the return type of
getvect which change in the same way according to the language used.
You obviously compiled your program as a C++ program and not as a C
program because according to the compiler's message 'oldvec' is
declared as a "C interrupt" and getvect returns a "C++ interrupt".

the format for using get/set vect() in C, which look nothing like your C++ example is:
tick_isr_old = getvect(0x08);
setvect(0x08, (void interrupt (*)(void)) tick_isr);

As mentioned already, the functions getvect() and setvect() are only available with Borland/Turbo C++. The functions _dos_getvect() and _dos_setvect() are almost identical and offer better portability across compilers (Borland/Turbo C++, MS Visual C++ 1.x, Open Watcom C++). They should be defined in <dos.h>.
Here is an example of their use (prints an '#' every second):
/*** Includes ***/
#include <stdint.h> // int*_t, uint*_t
#include <stdbool.h> // bool, true, false
#include <dos.h> // _chain_intr(), _dos_getvect() , _dos_setvect()
#include <stdio.h> // putchar()
/*** Definitions ***/
#define TICKS_PER_SEC 18ul
#define VECT_TIMER 0x1C
/*** Global Variables ***/
bool timer_hooked = false;
bool timer_1sec_elapsed = false;
uint32_t ticks = 0;
void (interrupt far * OrigTimerH)( ); // vector to original 0x1C handler
/*** Functions ***/
static void interrupt far TimerH( void ) {
ticks++;
if ( ticks % TICKS_PER_SEC == 0 ) {
timer_1sec_elapsed = true;
}
_chain_intr( OrigTimerH ); // handler callback
}
void TimerStart( void ) {
__asm { cli } // critical section; halt interrupts
OrigTimerH = _dos_getvect( VECT_TIMER ); // save original vector
_dos_setvect( VECT_TIMER, TimerH ); // put our handler in the vector
timer_hooked = true; // remember that we're hooked if we wanted to unhook
__asm { sti } // resume interrupts
}
int main( void ) {
TimerStart();
while ( true ) {
if ( timer_1sec_elapsed ) {
timer_1sec_elapsed = false;
putchar('#');
}
}
}

Related

Trouble storing a contents of a drive sector into character array using BIOS interrupt 0x13

We are working on a kernel in our Operating Systems class in C using bcc and some simulator software a professor wrote. The current step I am stuck on is to read a sector from a floppy using a 0x13 BIOS interrupt, storing it in a character array, and then printing it to the screen. Once we finish our kernel.c we build it into a floppy.img file. Then we load a .txt file into sector 30 of the floppy we are reading so we can test that our readSector function works properly. Finally we run the floppy.img file in a simulator that will simulate an OS
int main(){
void printString(char*);
void readString(char*);
void readSector(char*, int);
int mod(int, int);//Modulus Function
int div(int, int);//Divison Function
char buffer[512];
readSector(buffer,30);
printString(buffer);
while(1);
}
The printString function works fine and I have been using it for debugging purposes
void printString(char* chars){
int i;
for(i = 0; chars[i] != '\0'; i++){
interrupt(0x10, 0xe*256+chars[i], 0, 0, 0);
}
}//printString
We weren't really given a clear constructor for the 0x13 interrupt, I think this is the right order but I'm not 100%. When I run the simulator it prints the "Called interrupt 0x13" but doesn't print anything out after that, when it should print the contents of buffer from main.
void readSector(char* buffer, int sector){
int relativeSector = mod(sector,18)+1; //sector%18
int head = mod(div(sector,18),2); //(sector/18)%2
int track = div(sector,36); //sector/36
interrupt(0x13, 2, 1, buffer, track, relativeSector, head, 0); //0x13, AH, AL, BX, CH, CL, DH, DL
printString("Called interrupt 0x13\0");
}
Since bcc doesn't includ mod/div I made these based on some given pseudocode
int mod(int a, int b){//a == modulend, b == modulosor
while(a > b){
a =a-b;
}
return a;
}//mod
int div(int a, int b){//a == dividend, b == divisor, q == quotient
int q = 0;
while((q*b) <= a){
q++;
}
return q-1;
}//div
I'm not 100% sure how the 0x13 interrupt works, I assumed that it would read sector 30 and write it into the buffer array. My professor took a look at this for a few minutes and said it looks okay but wasn't sure why it wasn't working. Going to see him tomorrow to investigate this further, but there's a few more steps due by Wednesday and I'm getting antsy trying to figure this one out. Any help would be much appreciated

Save CPU registers to variables in GCC

I want get the values in EAX/EBX/ESP/EIP etc. and save them in C variables. For example:
int cEax;
asm("mov cEax,%eax"); ...
You can use this
register int eax asm("eax");
register int eax asm("ebx");
register int eax asm("esp");
//...
int cEax = eax;
int cEbx = ebx;
int cEsp = esp;
//...
You can also work with those registers in an expression just as any other variables or just use that register's value directly without assigning to another variable.
It's more tricky to get eip without inline assembly but in gcc you can get it with __builtin_return_address or the label as values extension.
void* getEIP()
{
return __builtin_return_address(0);
}
void *currentInstruction = getEIP();
currentAddr: void *nextInstruction = &&currentAddr;
If you want inline assembly you can use the way in this page

Compiler error while programming ic

MY friend is trying to program a shift register ic 74hc595 with 8051 microcontroller attached to display a moving led message.
But my compiler is giving me error in send_data(alf(a));
Here is code->
#include<8051.h>
#define clock P2_0
#define data_bit P2_1
#define latch P2_2
#define shift 8
void delay(unsigned int i)
{
int k=0;
while(k<i)
{
k++;
}
}
void send_data(unsigned char temp)
{
unsigned char i;
unsigned char dd;
latch=0;
clock=0;
for(i=0;i<shift;i++){
dd=temp>>i;
if(dd&1)
data_bit=1;
else
data_bit=0;
clock=1;
clock=0;
}
latch=1;
}
unsigned char alf[]={16,6,6,16};
void main()
{
unsigned char a;
while(1){
for(a=0;a<4;a++)
{
send_data(alf(a));
delay(10000);
}
}
}
Since its my friend who is making, i dont have much info about it. But if anything else is needed, please tell and i will provide but please help me solve this prob.
Thanks.
send_data(alf(a));
should be
send_data(alf[a]);
On the other hand, the body of delay can be optimized (and removed) by your compiler, take a look to the volatile keyword
In your case alf is an array not a function. If alf is a function then you can call alf(a). For array you need to pass index so you need to call alf[a].

Activate paging in kernel programming

I'm reading this tutorial "http://www.jamesmolloy.co.uk/tutorial_html/6.-Paging.html" about kenrel programming and the author is using the below struct to build the page directory
typedef struct page_directory
{
/**
Array of pointers to pagetables.
**/
page_table_t *tables[1024];
/**
Array of pointers to the pagetables above, but gives their *physical*
location, for loading into the CR3 register.
**/
u32int tablesPhysical[1024];
/**
The physical address of tablesPhysical. This comes into play
when we get our kernel heap allocated and the directory
may be in a different location in virtual memory.
**/
u32int physicalAddr;
} page_directory_t;
my question is why he is loading the address of the page directory like this in the function void switch_page_directory(page_directory_t *new);
asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhysical));
and not like this
asm volatile("mov %0, %%cr3":: "r"(current_directory ));
I've been testing with as shown in the code below
#include<stdio.h>
#include<stdlib.h>
typedef struct page
{
unsigned int present : 1; // Page present in memory
unsigned int rw : 1; // Read-only if clear, readwrite if set
unsigned int user : 1; // Supervisor level only if clear
unsigned int accessed : 1; // Has the page been accessed since last refresh?
unsigned int dirty : 1; // Has the page been written to since last refresh?
unsigned int unused : 7; // Amalgamation of unused and reserved bits
unsigned int frame : 20; // Frame address (shifted right 12 bits)
} page_t;
typedef struct page_table
{
page_t pages[1024];
} page_table_t;
typedef struct page_directory
{
page_table_t *tables[1024];
unsigned int tablesPhysical[1024];
unsigned int physicalAddr;
} page_directory_t;
int main()
{
page_directory_t *n;
n = malloc(sizeof(page_directory_t));
printf("n=%p i=%p y=%p\n", n,&n->tablesPhysical, &n->tables);
}
the result is below
n=0x833b008 i=0x833c008 y=0x833b008
I'm not sure why the address is always the same for the printf?
your function is not written correctly, and you don't include the whole relevant code in the question.
That said, I'd say that the text is unclear, but I'd read the Multitasking segment, which covers what current_directory is eventually used for.

Implementing thread-local storage in custom libc

I'm implementing a small subset of libc for very small and statically linked programs, and I figured that adding TLS support would be a good learning experience. I use Ulrich Drepper's TLS document as a reference.
I have two strings set up to try this out:
static __thread const char msg1[] = "TLS (1).\n"; /* 10 bytes */
static __thread const char msg2[] = "TLS (2).\n"; /* 10 bytes */
And the compiler generates the following instructions to access them:
mov rbx, QWORD PTR fs:0x0 ; Load TLS.
lea rsi, [rbx-0x14] ; Get a pointer to 'msg1'. 20 byte offset.
lea rsi, [rbx-0xa] ; Get a pointer to 'msg2'. 10 byte offset.
Let's assume I place the TCB somewhere on the stack:
struct tcb {
void* self; /* Points to self. I read that this was necessary somewhere. */
int errno; /* Per-thread errno variable. */
int padding;
};
And then place the TLS area just next to it at tls = &tcb - tls_size. Then I set the FS register to point at fs = tls + tls_size, and copy the TLS initialization image to tls.
However, this doesn't work. I have verified that I locate the TLS initialization image properly by writing the 20 bytes at tls_image to stdout. This either leads me to believe that I place the TCB and/or TLS area incorrectly, or that I'm otherwise not conforming to the ABI.
I set the FS register using arch_prctl(2). Do I need to use set_thread_area(2) somehow?
I don't have a dtv. I'm assuming this isn't necessary since I am linking statically.
Any ideas as to what I'm doing wrong? Thanks a lot!
I'm implementing a small subset of libc for very small and statically
linked programs, and I figured that adding TLS support would be a good
learning experience.
Awesome idea! I had to implement my own TLS in a project because I could not use any common thread library like pthread. I do not have a completely solution for your problems, but sharing my experience could be useful.
I set the FS register using arch_prctl(2). Do I need to use
set_thread_area(2) somehow?
The answer depends on the architecture, you are actually using. If you are using a x86-64 bit, you should use exclusively arch_prctl to set the FS register to an area of memory that you want to use as TLS (it allows you to address memory areas bigger than 4GB). While for x86-32 you must use set_thread_area as it is the only system call supported by the kernel.
The idea behind my implementation is to allocate a private memory area for each thread and save its address into the %GS register. It is a rather easy method, but in my case, it worked quite well. Each time you want to access the private area of a thread you just need to use as base address the value saved in %GS and an offset which identifies a memory location. I usually allocate a memory page (4096) for each thread and I divide it in 8 bytes blocks. So, I have 512 private memory slots for each thread, which can be accessed like an array whose indexes span from 0 to 511.
This is the code I use :
#define _GNU_SOURCE 1
#include "tls.h"
#include <asm/ldt.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <asm/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
void * install_tls() {
void *addr = mmap(0, 4096, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (syscall(SYS_arch_prctl,ARCH_SET_GS, addr) < 0)
return NULL;
return addr;
}
void freeTLS() {
void *addr;
syscall(SYS_arch_prctl,ARCH_GET_GS, &addr);
munmap(addr, 4096);
}
bool set_tls_value(int idx, unsigned long val) {
if (idx < 0 || idx >= 4096/8) {
return false;
}
asm volatile(
"movq %0, %%gs:(%1)\n"
:
: "q"((void *)val), "q"(8ll * idx));
return true;
}
unsigned long get_tls_value(int idx) {
long long rc;
if (idx < 0 || idx >= 4096/8) {
return 0;
}
asm volatile(
"movq %%gs:(%1), %0\n"
: "=q"(rc)
: "q"(8ll * idx));
return rc;
}
This is the header with some macros :
#ifndef TLS_H
#define TLS_H
#include <stdbool.h>
void *install_tls();
void freeTLS();
bool set_tls_value (int, unsigned long);
unsigned long get_tls_value(int );
/*
*macros used to set and retrieve the values
from the tls area
*/
#define TLS_TID 0x0
#define TLS_FD 0x8
#define TLS_MONITORED 0x10
#define set_local_tid(_x) \
set_tls_value(TLS_TID, (unsigned long)_x)
#define set_local_fd(_x) \
set_tls_value(TLS_FD, (unsigned long)_x)
#define set_local_monitored(_x) \
set_tls_value(TLS_MONITORED, (unsigned long)_x)
#define get_local_tid() \
get_tls_value(TLS_TID)
#define get_local_fd() \
get_tls_value(TLS_FD)
#define get_local_monitored() \
get_tls_value(TLS_MONITORED)
#endif /* end of include guard: TLS_H */
The first action to be accomplished by each thread is to install the TLS memory area. Once the TLS are has been initialized, each thread can start using this area as private TLS.

Resources